diff options
Diffstat (limited to 'src')
46 files changed, 743 insertions, 640 deletions
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 659f78970..985fcce11 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -13,7 +13,6 @@ export enum DocumentType { INK = "ink", // ink stroke SCREENSHOT = "screenshot", // view of a desktop application FONTICON = "fonticonbox", // font icon - MENUICON = "menuiconbox", QUERY = "query", // search query LABEL = "label", // simple text label BUTTON = "button", // onClick button diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 967ec08fd..539341b62 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -93,6 +93,7 @@ export interface DocumentOptions { type?: string; title?: string; label?: string; + hidden?: boolean; toolTip?: string; // tooltip to display on hover style?: string; page?: number; @@ -157,7 +158,7 @@ export interface DocumentOptions { annotationOn?: Doc; removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document dbDoc?: Doc; - menuIcon?: boolean; // if the font icon box is in the menu + iconShape?: string; // shapes of the fonticon border linkRelationship?: string; // type of relatinoship a link represents ischecked?: ScriptField; // returns whether a font icon box is checked activeInkPen?: Doc; // which pen document is currently active (used as the radio button state for the 'unhecked' pen tool scripts) @@ -173,6 +174,7 @@ export interface DocumentOptions { clipboard?: Doc; UseCors?: boolean; icon?: string; + target?: Doc; // available for use in scripts as the primary target document sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script searchFileTypes?: List<string>; // file types allowed in a search query diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 7b6868f73..8023df8b4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -12,7 +12,7 @@ import { Cast, PromiseValue, StrCast, NumCast } from "../../fields/Types"; import { nullAudio } from "../../fields/URLField"; import { DragManager } from "./DragManager"; import { Scripting } from "./Scripting"; -import { CollectionViewType } from "../views/collections/CollectionView"; +import { CollectionViewType, CollectionView } from "../views/collections/CollectionView"; import { makeTemplate } from "./DropConverter"; import { RichTextField } from "../../fields/RichTextField"; import { PrefetchProxy } from "../../fields/Proxy"; @@ -38,17 +38,7 @@ export class CurrentUserUtils { @observable public static GuestWorkspace: Doc | undefined; @observable public static GuestMobile: Doc | undefined; - @observable public static toolsBtn: any | undefined; - @observable public static libraryBtn: any | undefined; - @observable public static searchBtn: any | undefined; - - @observable public static toolsStack: any | undefined; - @observable public static workspaceStack: any | undefined; - @observable public static catalogStack: any | undefined; - @observable public static closedStack: any | undefined; - @observable public static searchStack: any | undefined; - - @observable public static selectedPanel: string = "none"; + @observable public static propertiesWidth: number = 0; // sets up the default User Templates - slideView, queryView, descriptionView static setupUserTemplateButtons(doc: Doc) { @@ -258,6 +248,8 @@ export class CurrentUserUtils { if (doc["template-buttons"] === undefined) { doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, { title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", + hidden: ComputedField.MakeFunction("self.target.noviceMode") as any, + target: doc, _autoHeight: true, _width: 500, _columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), })); @@ -441,7 +433,7 @@ export class CurrentUserUtils { { toolTip: "Drag a collection", title: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, { toolTip: "Drag a web page", title: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc }, { toolTip: "Drag a cat image", title: "Image", icon: "cat", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyImage as Doc }, - { toolTip: "Drag a comparison box", title: "Comp", icon: "columns", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyComparison as Doc }, + { toolTip: "Drag a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyComparison as Doc }, { toolTip: "Drag a screengrabber", title: "Grab", icon: "photo-video", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScreenshot as Doc }, // { title: "Drag a webcam", title: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, { toolTip: "Drag a audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyAudio as Doc }, @@ -477,7 +469,7 @@ export class CurrentUserUtils { } const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, ischecked, activeInkPen, backgroundColor, dragFactory }) => Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, + _nativeWidth: 50, _nativeHeight: 50, _width: 50, _height: 50, icon, title, toolTip, @@ -508,39 +500,54 @@ export class CurrentUserUtils { title: string, icon: string, click: string, }[] { return [ - { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu("Workspace")' }, - { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu("Catalog")' }, - { title: "Archive", icon: "archive", click: 'scriptContext.selectMenu("Archive")' }, - { title: "Import", icon: "upload", click: 'scriptContext.selectMenu("Import")' }, - { title: "Sharing", icon: "users", click: 'scriptContext.selectMenu("Sharing")' }, - { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu("Tools")' }, - { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu("Help")' }, - { title: "Settings", icon: "cog", click: 'scriptContext.selectMenu("Settings")' }, + { title: "Sharing", icon: "users", click: 'scriptContext.selectMenu(self, "Sharing")' }, + { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu(self, "Workspace")' }, + { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu(self, "Catalog")' }, + { title: "Archive", icon: "archive", click: 'scriptContext.selectMenu(self, "Archive")' }, + { title: "Import", icon: "upload", click: 'scriptContext.selectMenu(self, "Import")' }, + { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu(self, "Tools")' }, + { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu(self, "Help")' }, + { title: "Settings", icon: "cog", click: 'scriptContext.selectMenu(self, "Settings")' }, + { title: "User Doc", icon: "address-card", click: 'scriptContext.selectMenu(self, "UserDoc")' }, ]; } static setupMenuPanel(doc: Doc) { if (doc.menuStack === undefined) { - const buttons = CurrentUserUtils.menuBtnDescriptions(); - const menuBtns = buttons.map(({ title, icon, click }) => Docs.Create.FontIconDocument({ - icon, - menuIcon: true, - title, - _backgroundColor: "black", - stayInCollection: true, - _width: 60, - _height: 60, - onClick: ScriptField.MakeScript(click, { scriptContext: "any" }), - })); + const menuBtns = CurrentUserUtils.menuBtnDescriptions().map(({ title, icon, click }) => + Docs.Create.FontIconDocument({ + icon, + iconShape: "square", + title, + _backgroundColor: "black", + stayInCollection: true, + childDropAction: "same", + _width: 60, + _height: 60, + onClick: ScriptField.MakeScript(click, { scriptContext: "any" }), + })); + const userDoc = menuBtns[menuBtns.length - 1]; + userDoc.target = doc; + userDoc.hidden = ComputedField.MakeFunction("self.target.noviceMode"); doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, { title: "menuItemPanel", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _backgroundColor: "black", _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled", })); } + // this resets all sidebar buttons to being deactivated + PromiseValue(Cast(doc.menuStack, Doc)).then(stack => { + stack && PromiseValue(stack.data).then(btns => { + DocListCastAsync(btns).then(bts => bts?.forEach(btn => { + btn.color = "white"; + btn._backgroundColor = ""; + })); + }) + }); return doc.menuStack as Doc; } @@ -643,10 +650,6 @@ export class CurrentUserUtils { return Cast(userDoc.thumbDoc, Doc); } - static setupLibrary(userDoc: Doc) { - return CurrentUserUtils.setupWorkspaces(userDoc); - } - // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) { @@ -670,29 +673,13 @@ export class CurrentUserUtils { doc.myColorPicker = new PrefetchProxy(color); } - if (doc["tabs-button-tools"] === undefined) { + if (doc["sidebar-tools"] === undefined) { const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], { - _width: 500, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, title: "tools stack", forceActive: true + title: "sidebar-tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, forceActive: true })) as any as Doc; - CurrentUserUtils.toolsStack = toolsStack; - - doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({ - _width: 35, _height: 25, title: "Tools", _fontSize: "10pt", - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: toolsStack, - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: toolsStack, - removeDropProperties: new List<string>(["lockedPosition"]), - stayInCollection: true, - hideFilterView: true, - targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), - })); + doc["sidebar-tools"] = toolsStack; } - (doc["tabs-button-tools"] as any as Doc).sourcePanel; // prefetch sourcePanel - - return doc["tabs-button-tools"] as any as Doc; } static setupWorkspaces(doc: Doc) { @@ -703,20 +690,21 @@ export class CurrentUserUtils { title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true, })); } - const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`); - (doc.myWorkspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]); - (doc.myWorkspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]); - - const workspaces = doc.myWorkspaces as Doc; + if (doc["sidebar-workspaces"] === undefined) { + const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`); + (doc.myWorkspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]); + (doc.myWorkspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]); - CurrentUserUtils.workspaceStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces], { - title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true, - lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" - })) as any as Doc; + const workspaces = doc.myWorkspaces as Doc; - return doc.myWorkspaces as Doc; + doc["sidebar-workspaces"] = new PrefetchProxy(Docs.Create.TreeDocument([workspaces], { + treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true, + lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" + })) as any as Doc; + } } + static setupCatalog(doc: Doc) { doc.myCatalog === undefined; if (doc.myCatalog === undefined) { @@ -726,15 +714,16 @@ export class CurrentUserUtils { })); } - const catalog = doc.myCatalog as Doc; + if (doc["sidebar-catalog"] === undefined) { + const catalog = doc.myCatalog as Doc; - CurrentUserUtils.catalogStack = new PrefetchProxy(Docs.Create.TreeDocument([catalog], { - title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true, - lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" - })) as any as Doc; - - return doc.myCatalog as Doc; + doc["sidebar-catalog"] = new PrefetchProxy(Docs.Create.TreeDocument([catalog], { + title: "sidebar-catalog", + treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true, + lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" + })) as any as Doc; + } } static setupRecentlyClosed(doc: Doc) { // setup Recently Closed library item @@ -746,90 +735,51 @@ export class CurrentUserUtils { } // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready PromiseValue(Cast(doc.myRecentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast)); - const clearAll = ScriptField.MakeScript(`self.data = new List([])`); - (doc.myRecentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]); - (doc.myRecentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]); - - const recentlyClosed = doc.myRecentlyClosed as Doc; + if (doc["sidebar-recentlyClosed"] === undefined) { + const clearAll = ScriptField.MakeScript(`self.data = new List([])`); + (doc.myRecentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]); + (doc.myRecentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]); - CurrentUserUtils.closedStack = new PrefetchProxy(Docs.Create.TreeDocument([recentlyClosed], { - title: " ", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true, - lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" - })) as any as Doc; + const recentlyClosed = doc.myRecentlyClosed as Doc; - return doc.myRecentlyClosed as Doc; - } - // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views - static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) { - const workspaces = CurrentUserUtils.setupWorkspaces(doc); - const documents = CurrentUserUtils.setupCatalog(doc); - const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc); - - if (doc["tabs-button-library"] === undefined) { - const libraryStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], { - title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", - treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, + doc["sidebar-recentlyClosed"] = new PrefetchProxy(Docs.Create.TreeDocument([recentlyClosed], { + title: "sidebar-recentlyClosed", + treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true, lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" })) as any as Doc; - doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Library", _fontSize: "10pt", targetDropAction: "same", - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: libraryStack, - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: libraryStack, - removeDropProperties: new List<string>(["lockedPosition"]), - stayInCollection: true, - targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") - })); } - return doc["tabs-button-library"] as Doc; } - - // setup the Search button which will display the search panel. - static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) { - doc["tabs-button-search"] = undefined; - if (doc["tabs-button-search"] === undefined) { - doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Search", _fontSize: "10pt", - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc, - searchFileTypes: new List<string>([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]), - targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - lockedPosition: true, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") - })); - CurrentUserUtils.searchStack = new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc; + static setupUserDoc(doc: Doc) { + if (doc["sidebar-userDoc"] === undefined) { + doc.treeViewOpen = true; + doc.treeViewExpandedView = "fields"; + doc["sidebar-userDoc"] = new PrefetchProxy(Docs.Create.TreeDocument([doc], { + treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, title: "sidebar-userDoc", + treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, + lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same" + })) as any as Doc; } - return doc["tabs-button-search"] as any as Doc; } static setupSidebarContainer(doc: Doc) { - if (doc["tabs-panelContainer"] === undefined) { + if (doc["sidebar"] === undefined) { const sidebarContainer = new Doc(); sidebarContainer._chromeStatus = "disabled"; sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()"); - doc["tabs-panelContainer"] = new PrefetchProxy(sidebarContainer); + doc["sidebar"] = new PrefetchProxy(sidebarContainer); } - return doc["tabs-panelContainer"] as Doc; + return doc["sidebar"] as Doc; } // setup the list of sidebar mode buttons which determine what is displayed in the sidebar static async setupSidebarButtons(doc: Doc) { const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc); - CurrentUserUtils.toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer); - CurrentUserUtils.libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer); - CurrentUserUtils.searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer); - - // Finally, setup the list of buttons to display in the sidebar - if (doc["tabs-buttons"] === undefined) { - doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([CurrentUserUtils.libraryBtn, CurrentUserUtils.searchBtn, CurrentUserUtils.toolsBtn], { - _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", _columnsHideIfEmpty: true, ignoreClick: true, _chromeStatus: "view-mode", - title: "sidebar btn row stack", backgroundColor: "dimGray", - })); - (CurrentUserUtils.toolsBtn.onClick as ScriptField).script.run({ this: CurrentUserUtils.toolsBtn }); - } + await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer); + CurrentUserUtils.setupWorkspaces(doc); + CurrentUserUtils.setupCatalog(doc); + CurrentUserUtils.setupRecentlyClosed(doc); + CurrentUserUtils.setupUserDoc(doc); } static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { @@ -873,8 +823,8 @@ export class CurrentUserUtils { // Right sidebar is where mobile uploads are contained static setupRightSidebar(doc: Doc) { - if (doc.rightSidebarCollection === undefined) { - doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Mobile Uploads" })); + if (doc["sidebar-sharing"] === undefined) { + doc["sidebar-sharing"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Mobile Uploads" })); } } @@ -938,6 +888,8 @@ export class CurrentUserUtils { doc.activeDash = StrCast(doc.activeDash, "0"); doc.fontSize = StrCast(doc.fontSize, "12pt"); doc.fontFamily = StrCast(doc.fontFamily, "Arial"); + doc.fontColor = StrCast(doc.fontColor, "black"); + doc.fontHighlight = StrCast(doc.fontHighlight, ""); doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 5215ea35f..229a846a9 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -68,7 +68,7 @@ export default class GroupManager extends React.Component<{}> { const evaluating = raw.map(async user => { const userDocument = await DocServer.GetRefField(user.userDocumentId); if (userDocument instanceof Doc) { - const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); + const notificationDoc = await Cast(userDocument["sidebar-sharing"], Doc); runInAction(() => { if (notificationDoc instanceof Doc) { this.users.push(user.email); diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss index c1627e69f..6923fe879 100644 --- a/src/client/util/SettingsManager.scss +++ b/src/client/util/SettingsManager.scss @@ -7,7 +7,7 @@ height: 300px; button { - background: $lighter-alt-accent; + background: #315a96; outline: none; border-radius: 5px; border: 0px; @@ -29,8 +29,12 @@ button { width: 100%; align-self: center; - background: $darker-alt-accent; + background: #252b33; margin-top: 4px; + + &:hover { + background: $main-accent; + } } .delete-button { @@ -102,11 +106,12 @@ } h1 { - color: $dark-color; + color: #121721; text-transform: uppercase; letter-spacing: 2px; - font-size: 120%; + font-size: 19; margin-top: 0; + font-weight: bold; } .container { @@ -151,7 +156,7 @@ .settings-interface button { width: 100%; font-size: 30px; - background: #b2cef8; + background: #315a96; } .settings-interface .settings-heading { diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 207c78964..6276fae96 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -136,7 +136,7 @@ export default class SettingsManager extends React.Component<{}> { {this.errorText ? <div className="error-text">{this.errorText}</div> : undefined} {this.successText ? <div className="success-text">{this.successText}</div> : undefined} <button onClick={this.dispatchRequest}>submit</button> - <a href="/forgotPassword">forgot password?</a> + <a style={{ marginLeft: 65, marginTop: -20 }} href="/forgotPassword">forgot password?</a> </div> : undefined} diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 7a0fe4140..9d91ce1ba 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -114,7 +114,7 @@ export default class SharingManager extends React.Component<{}> { } /** - * Populates the list of validated users (this.users) by adding registered users which have a rightSidebarCollection. + * Populates the list of validated users (this.users) by adding registered users which have a sidebar-sharing. */ populateUsers = async () => { runInAction(() => this.users = []); @@ -125,7 +125,7 @@ export default class SharingManager extends React.Component<{}> { if (isCandidate) { const userDocument = await DocServer.GetRefField(user.userDocumentId); if (userDocument instanceof Doc) { - const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); + const notificationDoc = await Cast(userDocument["sidebar-sharing"], Doc); runInAction(() => { if (notificationDoc instanceof Doc) { this.users.push({ user, notificationDoc }); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 23a3e1684..d45531b76 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -278,9 +278,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV <div className="documentButtonBar-button"> <DocumentLinksButton links={this.view0.allLinks} View={this.view0} AlwaysOn={true} InMenu={true} StartLink={true} /> </div> - {DocumentLinksButton.StartLink ? <div className="documentButtonBar-button"> + {DocumentLinksButton.StartLink || !Doc.UserDoc()["documentLinksButton-hideEnd"] ? <div className="documentButtonBar-button"> <DocumentLinksButton links={this.view0.allLinks} View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} /> - </div> : null} + </div> : (null)} {/* <div className="documentButtonBar-button"> {this.templateButton} </div> diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index dd5303904..f16cb273b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -26,6 +26,7 @@ import { Tooltip } from '@material-ui/core'; import { GetEffectiveAcl } from '../../fields/util'; import { DocumentIcon } from './nodes/DocumentIcon'; import { render } from 'react-dom'; +import { createLessThan } from 'typescript'; library.add(faCaretUp); library.add(faObjectGroup); @@ -156,8 +157,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (e.button === 0 && !e.altKey && !e.ctrlKey) { let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; while (child.children.length) { - const next = Array.from(child.children).find(c => typeof (c.className) !== "string"); - if (typeof (next?.className) === "string" && next?.className.includes("documentView-node")) break; + const next = Array.from(child.children).find(c => typeof (c.className) === "string"); + if (next?.className.includes("documentView-node")) break; if (next) child = next; else break; } @@ -618,9 +619,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> </div>} </> : <> - {/* {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}> - <FontAwesomeIcon size="lg" icon="bars" /> - </div></Tooltip>} */} + {minimal ? (null) : <Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}> + <FontAwesomeIcon size="lg" icon="cog" /> + </div></Tooltip>} <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} > <span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span> </div> diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 5892e8346..8e3f72cee 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -178,7 +178,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume if (cm) { !Doc.UserDoc().noviceMode && cm.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); cm.addItem({ description: "Make Mask", event: this.makeMask, icon: "paint-brush" }); - cm.addItem({ description: "Format Shape...", event: this.formatShape, icon: "paint-brush" }); + //cm.addItem({ description: "Format Shape...", event: this.formatShape, icon: "paint-brush" }); } }} ><defs> diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 054a409df..a57d22afd 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -105,7 +105,7 @@ .mainView-propertiesDragger { background-color: rgb(140, 139, 139); height: 55px; - width: 15.5px; + width: 17px; position: absolute; top: 55%; border: 1px black solid; @@ -119,7 +119,7 @@ width: 10px; height: 10px; float: left; - margin-left: 3px; + margin-left: 5.5px; padding-top: 19px; } @@ -297,7 +297,7 @@ position: absolute; z-index: 2; touch-action: none; - cursor: ew-resize; + cursor: grab; .mainView-libraryHandle-icon { width: 10px; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 18d5c53c6..138ff226f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -79,9 +79,8 @@ export class MainView extends React.Component { @computed private get userDoc() { return Doc.UserDoc(); } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; } @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } - @computed public get sidebarButtonsDoc() { return Cast(this.userDoc["tabs-buttons"], Doc) as Doc; } - @observable public sidebarContent: any = this.userDoc?.["tabs-panelContainer"]; + @observable public sidebarContent: any = this.userDoc?.["sidebar"]; @observable public panelContent: string = "none"; @observable public showProperties: boolean = false; public isPointerDown = false; @@ -91,8 +90,7 @@ export class MainView extends React.Component { } else { return undefined; } } - @observable _propertiesWidth: number = 0; - propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, this._propertiesWidth)); + propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, CurrentUserUtils.propertiesWidth)); @computed get propertiesIcon() { if (this.propertiesWidth() < 10) { @@ -141,6 +139,9 @@ export class MainView extends React.Component { MainView.Instance = this; this._urlState = HistoryUtil.parseUrl(window.location) || {} as any; // causes errors to be generated when modifying an observable outside of an action + + CurrentUserUtils.propertiesWidth = 0; + configure({ enforceActions: "observed" }); if (window.location.pathname !== "/home") { const pathname = window.location.pathname.substr(1).split("/"); @@ -149,7 +150,7 @@ export class MainView extends React.Component { if (type === "doc") { CurrentUserUtils.MainDocId = pathname[1]; if (!this.userDoc) { - runInAction(() => this.flyoutWidth = 0); + runInAction(() => this.closeFlyout()); DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt<Field>) => field instanceof Doc && (CurrentUserUtils.GuestTarget = field))); } @@ -172,7 +173,7 @@ export class MainView extends React.Component { fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper, fa.faDesktop, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, - fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH); + fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft); //Pres trail icons (just for the sake of merging) library.add(fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, faBuffer); @@ -290,7 +291,7 @@ export class MainView extends React.Component { } // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) setTimeout(async () => { - const col = this.userDoc && await Cast(this.userDoc.rightSidebarCollection, Doc); + const col = this.userDoc && await Cast(this.userDoc["sidebar-sharing"], Doc); col && Cast(col.data, listSpec(Doc)) && runInAction(() => MainViewNotifs.NotifsCol = col); }, 100); return true; @@ -317,7 +318,7 @@ export class MainView extends React.Component { if (this.panelContent === doc?.title) return "lightgrey"; if (this.darkScheme) { switch (doc?.type) { - case DocumentType.MENUICON: return "white"; + case DocumentType.FONTICON: return "white"; case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d"; case DocumentType.LINK: case DocumentType.COL: { @@ -327,7 +328,7 @@ export class MainView extends React.Component { } } else { switch (doc?.type) { - case DocumentType.MENUICON: return "black"; + case DocumentType.FONTICON: return "black"; case DocumentType.RTF: return "#f1efeb"; case DocumentType.BUTTON: case DocumentType.LABEL: return "lightgray"; @@ -379,28 +380,25 @@ export class MainView extends React.Component { @action onPropertiesPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - this._propertiesWidth = this._panelWidth - e.clientX; + CurrentUserUtils.propertiesWidth = this._panelWidth - e.clientX; return false; - }), returnFalse, action(() => this._propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false); + }), returnFalse, action(() => CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false); } @action onFlyoutPointerDown = (e: React.PointerEvent) => { - this.panelContent = "none"; if (this._flyoutTranslate) { setupMoveUpEvents(this, e, action((e: PointerEvent) => { this.flyoutWidth = Math.max(e.clientX, 0); - this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30; - if (this.flyoutWidth === 0) { - CurrentUserUtils.selectedPanel = "none"; + if (this.flyoutWidth < 5) { + this.panelContent = "none"; + this._lastButton && (this._lastButton.color = "white"); + this._lastButton && (this._lastButton._backgroundColor = ""); } return false; }), emptyFunction, action(() => { - this.flyoutWidth = this.flyoutWidth < 15 ? 250 : 0; - this.flyoutWidth && (this.sidebarButtonsDoc._columnWidth = this.flyoutWidth / 3 - 30); - if (this.flyoutWidth === 0) { - CurrentUserUtils.selectedPanel = "none"; - } + if (this.flyoutWidth < 15) MainView.expandFlyout(); + else this.closeFlyout(); })); } } @@ -422,7 +420,7 @@ export class MainView extends React.Component { <div className="mainView-contentArea" style={{ position: "relative", height: `100%`, width: "100%", overflow: "visible" }}> {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close" onPointerDown={this.closeFlyout}> - <FontAwesomeIcon icon="times" color="black" size="sm" /> + <FontAwesomeIcon icon="times" color="black" size="lg" /> </div> : null} <DocumentView @@ -457,7 +455,6 @@ export class MainView extends React.Component { } @computed get menuPanel() { - return <div className="mainView-menuPanel"> <DocumentView Document={Doc.UserDoc().menuStack as Doc} @@ -471,7 +468,7 @@ export class MainView extends React.Component { rootSelected={returnTrue} removeDocument={returnFalse} onClick={undefined} - ScreenToLocalTransform={this.mainContainerXf} + ScreenToLocalTransform={this.sidebarScreenToLocal} ContentScaling={returnOne} PanelWidth={() => 60} PanelHeight={this.getContentsHeight} @@ -493,44 +490,47 @@ export class MainView extends React.Component { @action @undoBatch closeFlyout = () => { - CurrentUserUtils.selectedPanel = "none"; + this._lastButton && (this._lastButton.color = "white"); + this._lastButton && (this._lastButton._backgroundColor = ""); this.panelContent = "none"; this.flyoutWidth = 0; } get groupManager() { return GroupManager.Instance; } + _lastButton: Doc | undefined; @action @undoBatch - selectMenu = (str: string) => { + selectMenu = (button: Doc, str: string) => { + this._lastButton && (this._lastButton.color = "white"); + this._lastButton && (this._lastButton._backgroundColor = ""); if (this.panelContent === str && this.flyoutWidth !== 0) { - CurrentUserUtils.selectedPanel = "none"; this.panelContent = "none"; this.flyoutWidth = 0; } else { - this.panelContent = str; - CurrentUserUtils.selectedPanel = str; - switch (this.panelContent) { - case "Tools": this.sidebarContent.proto = CurrentUserUtils.toolsStack; break; - case "Workspace": this.sidebarContent.proto = CurrentUserUtils.workspaceStack; break; - case "Catalog": this.sidebarContent.proto = CurrentUserUtils.catalogStack; break; - case "Archive": this.sidebarContent.proto = CurrentUserUtils.closedStack; break; - case "Settings": this.sidebarContent.proto = SettingsManager.Instance.open(); break; - case "Sharing": this.sidebarContent.proto = GroupManager.Instance.open(); break; + let panelDoc: Doc | undefined; + switch (this.panelContent = str) { + case "Tools": panelDoc = Doc.UserDoc()["sidebar-tools"] as Doc ?? undefined; break; + case "Workspace": panelDoc = Doc.UserDoc()["sidebar-workspaces"] as Doc ?? undefined; break; + case "Catalog": panelDoc = Doc.UserDoc()["sidebar-catalog"] as Doc ?? undefined; break; + case "Archive": panelDoc = Doc.UserDoc()["sidebar-recentlyClosed"] as Doc ?? undefined; break; + case "Settings": SettingsManager.Instance.open(); break; + case "Sharing": panelDoc = Doc.UserDoc()["sidebar-sharing"] as Doc ?? undefined; break; + case "UserDoc": panelDoc = Doc.UserDoc()["sidebar-userDoc"] as Doc ?? undefined; break; } - if (str === "Settings" || str === "Sharing" || str === "Help" || str === "Import") { - CurrentUserUtils.selectedPanel = "none"; - this.panelContent = "none"; - this.flyoutWidth = 0; - } else { + this.sidebarContent.proto = panelDoc; + if (panelDoc) { MainView.expandFlyout(); - } + button._backgroundColor = "lightgrey"; + button.color = "black"; + this._lastButton = button; + } else this.flyoutWidth = 0; } return true; } @action @undoBatch closeProperties = () => { - this._propertiesWidth = 0; + CurrentUserUtils.propertiesWidth = 0; } @computed get propertiesView() { @@ -556,7 +556,7 @@ export class MainView extends React.Component { <div className="mainView-flyoutContainer" style={{ width: this.flyoutWidth }}> {this.flyoutWidth !== 0 ? <div className="mainView-libraryHandle" onPointerDown={this.onFlyoutPointerDown} - style={{ backgroundColor: this.defaultBackgroundColors(undefined) }}> + style={{ backgroundColor: 'lightgrey' }}> <span title="library View Dragger" style={{ width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw", //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh", @@ -564,7 +564,8 @@ export class MainView extends React.Component { top: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "" : "0" }} /> <div className="mainview-libraryHandle-icon"> - <FontAwesomeIcon icon="chevron-left" color="black" size="sm" /> </div> + <FontAwesomeIcon icon="chevron-left" color="black" size="sm" /> + </div> </div> : null} <div className="mainView-libraryFlyout" style={{ //transformOrigin: this._flyoutTranslate ? "" : "left center", @@ -577,9 +578,10 @@ export class MainView extends React.Component { </div> </div> {this.dockingContent} + <MainViewNotifs /> {this.showProperties ? (null) : <div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onPropertiesPointerDown} - style={{ right: rightFlyout, top: "45%" }}> + style={{ right: rightFlyout, top: "50%" }}> <div className="mainView-propertiesDragger-icon"> <FontAwesomeIcon icon={this.propertiesIcon} color="white" size="sm" /> </div> </div> @@ -614,7 +616,7 @@ export class MainView extends React.Component { public static expandFlyout = action(() => { MainView.Instance._flyoutTranslate = true; MainView.Instance.flyoutWidth = (MainView.Instance.flyoutWidth || 250); - MainView.Instance.sidebarButtonsDoc._columnWidth = MainView.Instance.flyoutWidth / 3 - 30; + }); @computed get expandButton() { @@ -635,7 +637,6 @@ export class MainView extends React.Component { if (dockedBtns instanceof Doc) { return <div className="mainView-docButtons" ref={this._docBtnRef} style={{ height: !dockedBtns.linearViewIsExpanded ? "42px" : undefined }} > - <MainViewNotifs /> <CollectionLinearView Document={dockedBtns} DataDoc={undefined} @@ -643,6 +644,7 @@ export class MainView extends React.Component { fieldKey={"data"} dropAction={"alias"} annotationsKey={""} + backgroundColor={this.defaultBackgroundColors} rootSelected={returnTrue} bringToFront={emptyFunction} select={emptyFunction} diff --git a/src/client/views/MainViewNotifs.scss b/src/client/views/MainViewNotifs.scss index 25ec95643..92d7d6ee3 100644 --- a/src/client/views/MainViewNotifs.scss +++ b/src/client/views/MainViewNotifs.scss @@ -1,5 +1,7 @@ .mainNotifs-container { position:absolute; + z-index: 1000; + top: 12px; .mainNotifs-badge { position: absolute; diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx index 05f890485..ce47e1cf1 100644 --- a/src/client/views/MainViewNotifs.tsx +++ b/src/client/views/MainViewNotifs.tsx @@ -3,28 +3,33 @@ import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { emptyFunction } from '../../Utils'; -import { SetupDrag } from '../util/DragManager'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../Utils'; +import { SetupDrag, DragManager } from '../util/DragManager'; import "./MainViewNotifs.scss"; -import { CollectionDockingView } from './collections/CollectionDockingView'; +import { MainView } from './MainView'; @observer export class MainViewNotifs extends React.Component { - @observable static NotifsCol: Opt<Doc>; - openNotifsCol = () => { - if (MainViewNotifs.NotifsCol) { - CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol); - } + _notifsRef = React.createRef<HTMLDivElement>(); + + onPointerDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, + (e: PointerEvent) => { + const dragData = new DragManager.DocumentDragData([MainViewNotifs.NotifsCol!]); + DragManager.StartDocumentDrag([this._notifsRef.current!], dragData, e.x, e.y); + return true; + }, + returnFalse, + () => MainViewNotifs.NotifsCol && MainView.Instance.selectMenu(MainViewNotifs.NotifsCol, "Sharing")); } + render() { const length = MainViewNotifs.NotifsCol ? DocListCast(MainViewNotifs.NotifsCol.data).length : 0; - const notifsRef = React.createRef<HTMLDivElement>(); - const dragNotifs = action(() => MainViewNotifs.NotifsCol!); - return <div className="mainNotifs-container" ref={notifsRef}> + return <div className="mainNotifs-container" style={{ width: 15, height: 15 }} ref={this._notifsRef}> <button className="mainNotifs-badge" style={length > 0 ? { "display": "initial" } : { "display": "none" }} - onClick={this.openNotifsCol} onPointerDown={MainViewNotifs.NotifsCol ? SetupDrag(notifsRef, dragNotifs) : emptyFunction}> + onPointerDown={this.onPointerDown} > {length} </button> </div>; diff --git a/src/client/views/PropertiesButtons.scss b/src/client/views/PropertiesButtons.scss index e099122c4..1cba252de 100644 --- a/src/client/views/PropertiesButtons.scss +++ b/src/client/views/PropertiesButtons.scss @@ -45,13 +45,13 @@ $linkGap : 3px; } .propertiesButtons { - margin-top: $linkGap; + margin-top: 3px; grid-column: 1/4; - width: max-content; + width: 100%; height: auto; display: flex; flex-direction: row; - overflow-x: visible; + flex-wrap: wrap; } .onClickFlyout-editScript { @@ -69,6 +69,7 @@ $linkGap : 3px; width: 25px; border-radius: 5px; margin-right: 18px; + margin-bottom: 8px; } .propertiesButtons-linker { @@ -77,10 +78,19 @@ $linkGap : 3px; text-align: center; border-radius: 5px; pointer-events: auto; - color: $dark-color; - border: $dark-color 1px solid; + // color: $dark-color; + // border: $dark-color 1px solid; + background-color: #252b33; + color: #fcfbf7; transition: 0.2s ease all; margin-right: 5px; + padding-top: 5px; + + &:hover { + background: $main-accent; + transform: scale(1.05); + cursor: pointer; + } } .propertiesButtons-linker:hover { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 59e7cc7c8..d46c03470 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -29,6 +29,7 @@ import { ImageField } from '../../fields/URLField'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { DocumentType } from '../documents/DocumentTypes'; import { CollectionFreeFormView } from './collections/collectionFreeForm/CollectionFreeFormView'; +import { InkField } from '../../fields/InkField'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -208,7 +209,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isPinned = targetDoc && Doc.isDocPinned(targetDoc); return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}> <div className="propertiesButtons-linker" - style={{ backgroundColor: isPinned ? "white" : "rgb(37, 43, 51)", color: isPinned ? "black" : "white" }} + style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white" }} onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}> <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" /> @@ -238,6 +239,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { onAliasButtonDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction); } + @undoBatch onAliasButtonMoved = () => { if (this._dragRef.current) { const dragDocView = this.selectedDocumentView!; @@ -273,12 +275,17 @@ export class PropertiesButtons extends React.Component<{}, {}> { </div></Tooltip>; } + @undoBatch onCopy = () => { if (this.selectedDoc && this.selectedDocumentView) { - const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true); - copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); - copy.y = NumCast(this.selectedDoc.y) + 30; - this.selectedDocumentView.props.addDocument?.(copy); + // const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true); + // copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); + // copy.y = NumCast(this.selectedDoc.y) + 30; + // this.selectedDocumentView.props.addDocument?.(copy); + const alias = Doc.MakeAlias(this.selectedDoc); + alias.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); + alias.y = NumCast(this.selectedDoc.y) + 30; + this.selectedDocumentView.props.addDocument?.(alias); } } @@ -295,7 +302,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { </Tooltip>; } - @action + @action @undoBatch onLock = () => { this.selectedDocumentView?.toggleLockPosition(); } @@ -337,15 +344,19 @@ export class PropertiesButtons extends React.Component<{}, {}> { return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Delete Document"}</div></>}> <div className={"propertiesButtons-linkButton-empty"} - onPointerDown={() => { - this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document); - }}> + onPointerDown={this.deleteDocument}> {<FontAwesomeIcon className="propertiesButtons-icon" icon="trash-alt" size="sm" />} </div> </Tooltip>; } + @undoBatch + @action + deleteDocument = () => { + this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document); + } + @computed get sharingButton() { const targetDoc = this.selectedDoc; @@ -380,6 +391,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { } } + @undoBatch @action handleOptionChange = (e: any) => { const value = e.target.value; @@ -513,6 +525,49 @@ export class PropertiesButtons extends React.Component<{}, {}> { </Tooltip>; } + @undoBatch + @action + private makeMask = () => { + if (this.selectedDoc) { + this.selectedDoc._backgroundColor = "rgba(0,0,0,0.7)"; + this.selectedDoc.mixBlendMode = "hard-light"; + this.selectedDoc.color = "#9b9b9bff"; + this.selectedDoc.stayInCollection = true; + this.selectedDoc.isInkMask = true; + } + } + + @computed + get maskButton() { + const targetDoc = this.selectedDoc; + return !targetDoc ? (null) : <Tooltip + title={<><div className="dash-tooltip">Make Mask</div></>}> + <div className={"propertiesButtons-linkButton-empty"} + onPointerDown={this.makeMask}> + {<FontAwesomeIcon className="documentdecorations-icon" + color="white" icon="paint-brush" size="sm" />} + </div> + </Tooltip>; + } + + @computed + get contextButton() { + if (this.selectedDoc) { + return <Tooltip title={<><div className="dash-tooltip">Show Context</div></>}> + <div className={"propertiesButtons-linkButton-empty"}> + <ParentDocSelector Document={this.selectedDoc} addDocTab={(doc, where) => { + where === "onRight" ? CollectionDockingView.AddRightSplit(doc) : + this.selectedDocumentView?.props.addDocTab(doc, "onRight"); + return true; + }} /> + </div> + </Tooltip>; + } else { + return false; + } + + } + // @computed // get importButton() { // const targetDoc = this.selectedDoc; @@ -538,6 +593,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const considerPull = isText && this.considerGoogleDocsPull; const considerPush = isText && this.considerGoogleDocsPush; const isImage = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof ImageField; + const isInk = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof InkField; const isCollection = this.selectedDoc.type === DocumentType.COL ? true : false; const isFreeForm = this.selectedDoc._viewType === "freeform" ? true : false; @@ -560,39 +616,43 @@ export class PropertiesButtons extends React.Component<{}, {}> { <div className="propertiesButtons-button"> {this.downloadButton} </div> - </div> - <div className="propertiesButtons"> - <div className="propertiesButtons-button"> - {this.deleteButton} - </div> - <div className="propertiesButtons-button"> - {this.onClickButton} - </div> - <div className="propertiesButtons-button"> - {this.sharingButton} - </div> - <div className="propertiesButtons-button" style={{ display: !considerPush ? "none" : "" }}> - {this.considerGoogleDocsPush} - </div> - <div className="propertiesButtons-button" style={{ display: !considerPull ? "none" : "" }}> - {this.considerGoogleDocsPull} - </div> - <div className="propertiesButtons-button" style={{ display: !isImage ? "none" : "" }}> - {this.googlePhotosButton} - </div> - {/* <div className="propertiesButtons-button" style={{ display: !isCollection ? "none" : "" }}> + <div className="propertiesButtons-button"> + {this.deleteButton} + </div> + <div className="propertiesButtons-button"> + {this.onClickButton} + </div> + {/* <div className="propertiesButtons-button"> + {this.contextButton} + </div> */} + <div className="propertiesButtons-button"> + {this.sharingButton} + </div> + <div className="propertiesButtons-button" style={{ display: !considerPush ? "none" : "" }}> + {this.considerGoogleDocsPush} + </div> + <div className="propertiesButtons-button" style={{ display: !considerPull ? "none" : "" }}> + {this.considerGoogleDocsPull} + </div> + <div className="propertiesButtons-button" style={{ display: !isImage ? "none" : "" }}> + {this.googlePhotosButton} + </div> + {/* <div className="propertiesButtons-button" style={{ display: !isCollection ? "none" : "" }}> {this.importButton} </div> */} - <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}> - {this.clustersButton} - </div> + <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}> + {this.clustersButton} + </div> - <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}> - {this.fitContentButton} - </div> + <div className="propertiesButtons-button" style={{ display: !isFreeForm ? "none" : "" }}> + {this.fitContentButton} + </div> + <div className="propertiesButtons-button" style={{ display: !isInk ? "none" : "" }}> + {this.maskButton} </div> + </div> </div>; } } diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 6d93b2ba8..857f751d3 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -113,6 +113,20 @@ .lm_header .lm_tab { padding-right: 20px; + margin-top: -1px; + border-bottom: 1px black; + .collectionDockingView-gear { + display: none; + } +} + +.lm_header .lm_tab.lm_active { + padding-right: 20px; + margin-top: 1px; + border-bottom: unset; + .collectionDockingView-gear { + display: inline-block; + } } .lm_popout { @@ -145,10 +159,7 @@ padding-left: 5px; height: 15px; width: 18px; - display: inline-block; margin: auto; - - display: none; } .collectionDockingView-dragAsDocument { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 7d6e67177..9c85bd0a2 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -772,6 +772,10 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { private onActiveContentItemChanged() { if (this.props.glContainer.tab) { this._isActive = this.props.glContainer.tab.isActive; + setTimeout(() => { + const dv = this._document && DocumentManager.Instance.getFirstDocumentView(this._document); + dv && SelectionManager.SelectDoc(dv, false); + }); !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. } } diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index 3b31947f7..a9e812ad3 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -161,7 +161,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { PanelHeight={nested ? pair.layout[HeightSym] : () => this.dimension()} renderDepth={this.props.renderDepth + 1} focus={emptyFunction} - backgroundColor={returnEmptyString} + backgroundColor={this.props.backgroundColor} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss index 7201afcc0..b41cbe92d 100644 --- a/src/client/views/collections/CollectionMenu.scss +++ b/src/client/views/collections/CollectionMenu.scss @@ -404,14 +404,14 @@ .collectionSchemaViewChrome-toggler { width: 100px; - height: 41px; + height: 35px; background-color: black; position: relative; } .collectionSchemaViewChrome-togglerButton { width: 47px; - height: 35px; + height: 30px; background-color: $light-color-secondary; // position: absolute; transition: all 0.5s ease; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 59e6ac7ff..a7d2c07fa 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -30,6 +30,8 @@ import { RichTextField } from "../../../fields/RichTextField"; import { ScriptField } from "../../../fields/ScriptField"; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { DocUtils } from "../../documents/Documents"; +import { Tooltip } from "@material-ui/core"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; @observer export default class CollectionMenu extends AntimodeMenu { @@ -65,16 +67,37 @@ export default class CollectionMenu extends AntimodeMenu { } } + @action + toggleProperties = () => { + if (CurrentUserUtils.propertiesWidth > 0) { + CurrentUserUtils.propertiesWidth = 0; + } else { + CurrentUserUtils.propertiesWidth = 250; + } + } + render() { - const button = <button className="antimodeMenu-button" key="pin menu" title="Pin menu" onClick={this.toggleMenuPin} style={{ backgroundColor: "#121721" }}> - <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} /> - </button>; + const button = <Tooltip title={<div className="dash-tooltip">Pin Menu</div>} key="pin menu" placement="bottom"> + <button className="antimodeMenu-button" onClick={this.toggleMenuPin} style={{ backgroundColor: "#121721" }}> + <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} /> + </button> + </Tooltip>; + + const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left"; + const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Properties Panel" : "Open Properties Panel"; + + const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="properties" placement="bottom"> + <button className="antimodeMenu-button" key="properties" onPointerDown={this.toggleProperties}> + <FontAwesomeIcon icon={propIcon} size="lg" /> + </button> + </Tooltip>; return this.getElement(!this.SelectedCollection ? [button] : [<CollectionViewBaseChrome key="chrome" docView={this.SelectedCollection} fieldKey={Doc.LayoutFieldKey(this.SelectedCollection?.props.Document)} type={StrCast(this.SelectedCollection?.props.Document._viewType, CollectionViewType.Invalid) as CollectionViewType} />, + prop, button]); } } @@ -163,12 +186,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp }; @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; } - - _stacking_commands = [this._contentCommand, this._templateCommand]; - _masonry_commands = [this._contentCommand, this._templateCommand]; - _schema_commands = [this._templateCommand, this._narrativeCommand]; - _doc_commands = [this._openLinkInCommand, this._onClickCommand]; - _tree_commands = []; + @computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } + @computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; } + @computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; } + @computed get _doc_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._openLinkInCommand, this._onClickCommand]; } + @computed get _tree_commands() { return undefined; } private get _buttonizableCommands() { switch (this.props.type) { default: return this._doc_commands; @@ -188,7 +210,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp @observable private _currentKey: string = ""; componentDidMount = action(() => { - this._currentKey = this._currentKey || (this._buttonizableCommands.length ? this._buttonizableCommands[0]?.title : ""); + this._currentKey = this._currentKey || (this._buttonizableCommands?.length ? this._buttonizableCommands[0]?.title : ""); }); @undoBatch @@ -238,7 +260,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp protected drop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; if (docDragData?.draggedDocuments.length) { - this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || [])); + this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || [])); e.stopPropagation(); } return true; @@ -260,54 +282,58 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp } dragCommandDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e, down, delta) => { - this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => + this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title, { target: this.document }, c.params, c.initialize, e.clientX, e.clientY)); return true; }, emptyFunction, () => { - this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate([])); + this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate([])); }); } @computed get templateChrome() { return <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} > - <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}> - <button className={"antimodeMenu-button"} > - <FontAwesomeIcon icon="bullseye" size="lg" /> - </button> - <select - className="collectionViewBaseChrome-cmdPicker" onPointerDown={stopPropagation} onChange={this.commandChanged} value={this._currentKey}> - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""} /> - {this._buttonizableCommands.map(cmd => - <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option> - )} - </select> - </div> + <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom"> + <div className="commandEntry-outerDiv" ref={this._commandRef} onPointerDown={this.dragCommandDown}> + <button className={"antimodeMenu-button"} > + <FontAwesomeIcon icon="bullseye" size="lg" /> + </button> + <select + className="collectionViewBaseChrome-cmdPicker" onPointerDown={stopPropagation} onChange={this.commandChanged} value={this._currentKey}> + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""} /> + {this._buttonizableCommands?.map(cmd => + <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option> + )} + </select> + </div> + </Tooltip> </div>; } @computed get viewModes() { return <div className="collectionViewBaseChrome-viewModes" > - <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._viewRef} onPointerDown={this.dragViewDown}> - <button className={"antimodeMenu-button"}> - <FontAwesomeIcon icon="bullseye" size="lg" /> - </button> - <select - className="collectionViewBaseChrome-viewPicker" - onPointerDown={stopPropagation} - onChange={this.viewChanged} - value={StrCast(this.props.type)}> - {Object.values(CollectionViewType).map(type => [CollectionViewType.Invalid, CollectionViewType.Docking].includes(type) ? (null) : ( - <option - key={Utils.GenerateGuid()} - className="collectionViewBaseChrome-viewOption" - onPointerDown={stopPropagation} - value={type}> - {type[0].toUpperCase() + type.substring(1)} - </option> - ))} - </select> - </div> + <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom"> + <div className="commandEntry-outerDiv" ref={this._viewRef} onPointerDown={this.dragViewDown}> + <button className={"antimodeMenu-button"}> + <FontAwesomeIcon icon="bullseye" size="lg" /> + </button> + <select + className="collectionViewBaseChrome-viewPicker" + onPointerDown={stopPropagation} + onChange={this.viewChanged} + value={StrCast(this.props.type)}> + {Object.values(CollectionViewType).map(type => [CollectionViewType.Invalid, CollectionViewType.Docking].includes(type) ? (null) : ( + <option + key={Utils.GenerateGuid()} + className="collectionViewBaseChrome-viewOption" + onPointerDown={stopPropagation} + value={type}> + {type[0].toUpperCase() + type.substring(1)} + </option> + ))} + </select> + </div> + </Tooltip> </div>; } @@ -317,9 +343,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp } else { return undefined; } } @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } - @computed get isText() { + @computed get notACollection() { if (this.selectedDoc) { - return this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof RichTextField; + const layoutField = Doc.LayoutField(this.selectedDoc); + return this.props.type === CollectionViewType.Docking || + typeof (layoutField) === "string" && !layoutField?.includes("CollectionView"); } else return false; } @@ -329,21 +357,25 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp <div className="collectionMenu-cont" > <div className="collectionMenu"> <div className="collectionViewBaseChrome"> - {this.props.type === CollectionViewType.Invalid || - this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.viewModes} - {this.props.type === CollectionViewType.Docking || this.isText ? (null) : this.templateChrome} - {Doc.UserDoc().noviceMode ? (null) : <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}> - <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} > - <FontAwesomeIcon icon="filter" size="lg" /> - </button> - </div>} - - {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) : <button className={"antimodeMenu-button"} key="float" - style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }} - title="Toggle Overlay Layer" - onClick={() => DocumentView.FloatDoc(this.props.docView)}> - <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} /> - </button>} + {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes} + {!this._buttonizableCommands ? (null) : this.templateChrome} + {Doc.UserDoc().noviceMode ? (null) : + <Tooltip title={<div className="dash-tooltip">filter documents to show</div>} placement="bottom"> + <div className="collectionViewBaseChrome-viewSpecs" style={{ display: "grid" }}> + <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} > + <FontAwesomeIcon icon="filter" size="lg" /> + </button> + </div> + </Tooltip>} + + {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) : + <Tooltip title={<div className="dash-tooltip">Toggle Overlay Layer</div>} placement="bottom"> + <button className={"antimodeMenu-button"} key="float" + style={{ backgroundColor: this.props.docView.layoutDoc.z ? "121212" : undefined, borderRight: "1px solid gray" }} + onClick={() => DocumentView.FloatDoc(this.props.docView)}> + <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} /> + </button> + </Tooltip>} </div> {this.subChrome} </div> @@ -418,10 +450,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""]; private _width = ["1", "5", "10", "100"]; - // private _draw = ["⎯", "→", "↔︎", "∿", "↝", "↭", "ロ", "O", "∆"]; - // private _head = ["", "", "arrow", "", "", "arrow", "", "", ""]; - // private _end = ["", "arrow", "arrow", "", "arrow", "arrow", "", "", ""]; - // private _shape = ["line", "line", "line", "", "", "", "rectangle", "circle", "triangle"]; private _dotsize = [10, 20, 30, 40]; private _draw = ["∿", "⎯", "→", "↔︎", "ロ", "O"]; private _head = ["", "", "", "arrow", "", ""]; @@ -491,22 +519,24 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu }); return <div className="btn-draw" key="draw"> {this._draw.map((icon, i) => - <button className="antimodeMenu-button" title={this._title[i]} key={icon} onPointerDown={() => func(i, false)} onDoubleClick={() => func(i, true)} - style={{ backgroundColor: i === this._selected ? "121212" : "", fontSize: "20" }}> - {/* {this._draw[i]} */} - <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" /> - - </button>)} + <Tooltip key={icon} title={<div className="dash-tooltip">{this._title[i]}</div>} placement="bottom"> + <button className="antimodeMenu-button" onPointerDown={() => func(i, false)} onDoubleClick={() => func(i, true)} + style={{ backgroundColor: i === this._selected ? "121212" : "", fontSize: "20" }}> + <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" /> + </button> + </Tooltip>)} </div>; } toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps["icon"], ele: JSX.Element | null) => { - return <button className="antimodeMenu-button" key={key} title={key} - onPointerDown={action(e => setter())} - style={{ backgroundColor: value ? "121212" : "" }}> - <FontAwesomeIcon icon={icon} size="lg" /> - {ele} - </button>; + return <Tooltip title={<div className="dash-tooltip">{key}</div>} placement="bottom"> + <button className="antimodeMenu-button" key={key} + onPointerDown={action(e => setter())} + style={{ backgroundColor: value ? "121212" : "" }}> + <FontAwesomeIcon icon={icon} size="lg" /> + {ele} + </button> + </Tooltip>; } @computed get widthPicker() { @@ -515,11 +545,13 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu <div className="btn2-group" key="width"> {widthPicker} {this._width.map((wid, i) => - <button className="antimodeMenu-button" key={wid} title="change width" - onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })} - style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: "center" }}> - • - </button>)} + <Tooltip title={<div className="dash-tooltip">change width</div>} placement="bottom"> + <button className="antimodeMenu-button" key={wid} + onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })} + style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: "center" }}> + • + </button> + </Tooltip>)} </div>; } @@ -554,56 +586,56 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu </div>; } - @computed get formatPane() { - // return <button className="antimodeMenu-button" key="format" title="toggle foramatting pane" - // onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)} - // style={{ backgroundColor: this._fillBtn ? "121212" : "" }}> - // <FontAwesomeIcon icon="angle-double-right" size="lg" /> - // </button>; - return null; - } - render() { - return !this.props.docView.layoutDoc ? (null) : <div className="collectionFreeFormMenu-cont"> - {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) : - <div key="map" title="mini map" className="backKeyframe" onClick={this.miniMap}> - <FontAwesomeIcon icon={"map"} size={"lg"} /> - </div> - } - {!!!this.isText ? <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}> - <FontAwesomeIcon icon={"caret-left"} size={"lg"} /> - </div> : null} - {!!!this.isText ? <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }} - onClick={action(() => this.document.editing = !this.document.editing)} > - {NumCast(this.document.currentFrame)} - </div> : null} - {!!!this.isText ? <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}> - <FontAwesomeIcon icon={"caret-right"} size={"lg"} /> - </div> : null} - - {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) : - <button className={"antimodeMenu-button"} key="hypothesis" - style={{ - backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, - borderRight: "1px solid gray" - }} - title="Use Hypothesis" - onClick={() => this.props.docView.layoutDoc.isAnnotating = !this.props.docView.layoutDoc.isAnnotating}> - <FontAwesomeIcon icon={["fab", "hire-a-helper"]} size={"lg"} /> - </button> - } - {(!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating) && !this.isText ? - <> - {this.drawButtons} - {this.widthPicker} - {this.colorPicker} - {this.fillPicker} - {this.formatPane} - </> : - (null) - } - {this.isText ? <RichTextMenu key="rich" /> : null} - </div>; + return !this.props.docView.layoutDoc ? (null) : + <div className="collectionFreeFormMenu-cont"> + {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) : + <Tooltip key="map" title={<div className="dash-tooltip">Toggle Mini Map</div>} placement="bottom"> + <div className="backKeyframe" onClick={this.miniMap}> + <FontAwesomeIcon icon={"map"} size={"lg"} /> + </div> + </Tooltip> + } + {!this.isText ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom"> + <div className="backKeyframe" onClick={this.prevKeyframe}> + <FontAwesomeIcon icon={"caret-left"} size={"lg"} /> + </div> + </Tooltip> : null} + {!this.isText ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom"> + <div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }} + onClick={action(() => this.document.editing = !this.document.editing)} > + {NumCast(this.document.currentFrame)} + </div> + </Tooltip> : null} + {!this.isText ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom"> + <div className="fwdKeyframe" onClick={this.nextKeyframe}> + <FontAwesomeIcon icon={"caret-right"} size={"lg"} /> + </div> + </Tooltip> : null} + + {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) : + <Tooltip key="hypothesis" title={<div className="dash-tooltip">Use Hypothesis</div>} placement="bottom"> + <button className={"antimodeMenu-button"} key="hypothesis" + style={{ + backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, + borderRight: "1px solid gray" + }} + onClick={() => this.props.docView.layoutDoc.isAnnotating = !this.props.docView.layoutDoc.isAnnotating}> + <FontAwesomeIcon icon={["fab", "hire-a-helper"]} size={"lg"} /> + </button> + </Tooltip> + } + {(!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating) && !this.isText ? + <> + {this.drawButtons} + {this.widthPicker} + {this.colorPicker} + {this.fillPicker} + </> : + (null) + } + {this.isText ? <RichTextMenu key="rich" /> : null} + </div>; } } @observer diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a104ac011..e00bdb065 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -45,7 +45,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) @observable _scroll = 0; // used to force the document decoration to update when scrolling @computed get columnHeaders() { return Cast(this.layoutDoc._columnHeaders, listSpec(SchemaHeaderField)); } @computed get pivotField() { return StrCast(this.layoutDoc._pivotField); } - @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout); } + @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.hidden).map(pair => pair.layout); } @computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); } @computed get yMargin() { return Math.max(this.layoutDoc._showTitle && !this.layoutDoc._showTitleHover ? 30 : 0, NumCast(this.layoutDoc._yMargin, 0)); } // 2 * this.gridGap)); } @computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c90e85271..3ebc6baca 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -185,13 +185,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; - ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); if (docDragData) { let added = false; - const dropaction = docDragData.dropAction || docDragData.userDropAction; - if (dropaction && dropaction !== "move") { - added = this.addDocument(docDragData.droppedDocuments); - } else if (docDragData.moveDocument) { + const dropAction = docDragData.dropAction || docDragData.userDropAction; + if ((!dropAction || dropAction === "move") && docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); const res = addedDocs.length ? this.addDocument(addedDocs) : true; @@ -201,6 +198,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse); } else added = res; } else { + ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); added = this.addDocument(docDragData.droppedDocuments); } added && e.stopPropagation(); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index bb5403930..8ec855c7c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -786,7 +786,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll onClicks.push({ description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.doc, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit" }); - !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" }); + !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" }); } outerXf = () => Utils.GetScreenTransform(this._mainEle!); onTreeDrop = (e: React.DragEvent) => this.onExternalDrop(e, {}); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c2b55d38e..89034a0c0 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -339,7 +339,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus icon: "edit", event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), })); - !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" }); + !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "mouse-pointer" }); if (!Doc.UserDoc().noviceMode) { const more = cm.findByDescription("More..."); diff --git a/src/client/views/collections/ParentDocumentSelector.scss b/src/client/views/collections/ParentDocumentSelector.scss index 4e704b58f..bc9cf4848 100644 --- a/src/client/views/collections/ParentDocumentSelector.scss +++ b/src/client/views/collections/ParentDocumentSelector.scss @@ -2,11 +2,13 @@ div { overflow: visible !important; } + .metadataEntry-outerDiv { overflow: hidden !important; pointer-events: all; } } + .parentDocumentSelector-flyout { position: relative; z-index: 9999; @@ -31,26 +33,31 @@ border-left: 0px; } } + .parentDocumentSelector-button { - pointer-events: all; + pointer-events: all; position: relative; display: inline-block; + svg { - width:20px !important; - height:20px; + // width:20px !important; + //height:20px; } } + .parentDocumentSelector-metadata { pointer-events: auto; padding-right: 5px; width: 25px; display: inline-block; } + .buttonSelector { div { overflow: visible !important; } - display: inline-block; + + display: inline-block; width:100%; height:100%; }
\ No newline at end of file diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 532dd6abc..4c8cac3ed 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -129,7 +129,7 @@ export class DockingViewButtonSelector extends React.Component<{ views: () => Do this.props.views()[0]?.select(false); }} className="buttonSelector"> <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}> - <FontAwesomeIcon icon={"cog"} size={"sm"} /> + <FontAwesomeIcon icon={"arrows-alt"} size={"sm"} /> </Flyout> </span>; } diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss index f559b940c..89124129b 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss @@ -60,6 +60,10 @@ padding-left: 8px; background-color: rgb(51, 51, 51); + &:hover { + cursor: pointer; + } + .propertiesView-settings-title-icon { float: right; right: 0; @@ -94,6 +98,10 @@ padding-left: 8px; background-color: rgb(51, 51, 51); + &:hover { + cursor: pointer; + } + .propertiesView-sharing-title-icon { float: right; right: 0; @@ -127,6 +135,10 @@ padding-left: 8px; background-color: rgb(51, 51, 51); + &:hover { + cursor: pointer; + } + .propertiesView-appearance-title-icon { float: right; right: 0; @@ -160,6 +172,10 @@ padding-left: 8px; background-color: rgb(51, 51, 51); + &:hover { + cursor: pointer; + } + .propertiesView-transform-title-icon { float: right; right: 0; @@ -287,6 +303,10 @@ padding-left: 8px; background-color: rgb(51, 51, 51); + &:hover { + cursor: pointer; + } + .propertiesView-fields-title-name { font-size: 12.5px; font-weight: bold; @@ -362,6 +382,10 @@ padding-left: 8px; background-color: rgb(51, 51, 51); + &:hover { + cursor: pointer; + } + .propertiesView-layout-title-icon { float: right; right: 0; diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index 3e54d001b..4c79a7c2f 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -9,10 +9,10 @@ $main-accent: #aaaaa3; //$alt-accent: #59dff7; $alt-accent: #c2c2c5; $lighter-alt-accent: rgb(207, 220, 240); -$darker-alt-accent: rgb(178, 206, 248); +$darker-alt-accent: #b2cef8; $intermediate-color: #9c9396; $dark-color: #121721; -$link-color: lightBlue; +$link-color: #add8e6; $antimodemenu-height: 35px; // fonts $sans-serif: "Noto Sans", diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 04329182e..660afd4b9 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -1,20 +1,16 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faArrowLeft, faCog, faEllipsisV, faExchangeAlt, faPlus, faTable, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable, computed, toJS } from "mobx"; +import { Tooltip } from "@material-ui/core"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt } from "../../../fields/Doc"; -import { StrCast, DateCast } from "../../../fields/Types"; +import { Doc } from "../../../fields/Doc"; +import { DateCast, StrCast } from "../../../fields/Types"; import { Utils } from "../../../Utils"; import { LinkManager } from "../../util/LinkManager"; +import { undoBatch } from "../../util/UndoManager"; import './LinkEditor.scss'; import React = require("react"); -import { DocumentView } from "../nodes/DocumentView"; -import { DocumentLinksButton } from "../nodes/DocumentLinksButton"; -import { EditableView } from "../EditableView"; -import { RefObject } from "react"; -import { Tooltip } from "@material-ui/core"; -import { undoBatch } from "../../util/UndoManager"; library.add(faArrowLeft, faEllipsisV, faTable, faTrash, faCog, faExchangeAlt, faTimes, faPlus); @@ -296,21 +292,18 @@ export class LinkEditor extends React.Component<LinkEditorProps> { //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION"; - @undoBatch - @action + @undoBatch @action deleteLink = (): void => { LinkManager.Instance.deleteLink(this.props.linkDoc); this.props.showLinks(); } - @action + @undoBatch @action setDescripValue = (value: string) => { if (LinkManager.currentLink) { LinkManager.currentLink.description = value; this.buttonColor = "rgb(62, 133, 55)"; - setTimeout(action(() => { - this.buttonColor = "black"; - }), 750); + setTimeout(action(() => this.buttonColor = "black"), 750); return true; } } @@ -362,7 +355,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { this.openDropdown = !this.openDropdown; } - @action + @undoBatch @action changeFollowBehavior = (follow: string) => { this.openDropdown = false; Doc.GetProto(this.props.linkDoc).followLinkLocation = follow; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 0aabf5319..6feb0a398 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -167,6 +167,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { DocumentLinksButton.EditLink = undefined; } + @undoBatch @action showLink = () => { this.props.linkDoc.hidden = !this.props.linkDoc.hidden; diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index f7e253f42..6081def5d 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -78,9 +78,6 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp render() { TraceMobx(); - if (this.props.Document.title === "Archive") { - console.log(""); - } return (<div className="contentFittingDocumentView" style={{ width: Math.abs(this.centeringYOffset) > 0.001 ? "auto" : this.props.PanelWidth(), height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(), diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 198a90225..4713ce447 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -4,7 +4,7 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../../fields/Doc"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils"; +import { emptyFunction, returnFalse, setupMoveUpEvents, emptyPath } from "../../../Utils"; import { DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { LinkManager } from "../../util/LinkManager"; @@ -67,7 +67,11 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => { if (doubleTap && this.props.InMenu && this.props.StartLink) { //action(() => Doc.BrushDoc(this.props.View.Document)); - DocumentLinksButton.StartLink = this.props.View; + if (DocumentLinksButton.StartLink === this.props.View) { + DocumentLinksButton.StartLink = undefined; + } else { + DocumentLinksButton.StartLink = this.props.View; + } } else if (!this.props.InMenu) { DocumentLinksButton.EditLink = this.props.View; DocumentLinksButton.EditLinkLoc = [e.clientX + 10, e.clientY]; @@ -78,7 +82,12 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp @action @undoBatch onLinkClick = (e: React.MouseEvent): void => { if (this.props.InMenu && this.props.StartLink) { - DocumentLinksButton.StartLink = this.props.View; + if (DocumentLinksButton.StartLink === this.props.View) { + DocumentLinksButton.StartLink = undefined; + } else { + DocumentLinksButton.StartLink = this.props.View; + } + //action(() => Doc.BrushDoc(this.props.View.Document)); } else if (!this.props.InMenu) { DocumentLinksButton.EditLink = this.props.View; @@ -86,77 +95,65 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp } } - @action @undoBatch completeLink = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e, doubleTap) => { - if (doubleTap && this.props.InMenu && !!!this.props.StartLink) { + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action((e, doubleTap) => { + if (doubleTap && this.props.InMenu && !this.props.StartLink) { if (DocumentLinksButton.StartLink === this.props.View) { DocumentLinksButton.StartLink = undefined; - } else { - - if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) { - const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); - LinkManager.currentLink = linkDoc; - - runInAction(() => { - if (linkDoc) { - TaskCompletionBox.textDisplayed = "Link Created"; - TaskCompletionBox.popupX = e.screenX; - TaskCompletionBox.popupY = e.screenY - 133; - TaskCompletionBox.taskCompleted = true; - - LinkDescriptionPopup.popupX = e.screenX; - LinkDescriptionPopup.popupY = e.screenY - 100; - LinkDescriptionPopup.descriptionPopup = true; + } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) { + const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); + LinkManager.currentLink = linkDoc; + if (linkDoc) { + TaskCompletionBox.textDisplayed = "Link Created"; + TaskCompletionBox.popupX = e.screenX; + TaskCompletionBox.popupY = e.screenY - 133; + TaskCompletionBox.taskCompleted = true; - setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500); - } + LinkDescriptionPopup.popupX = e.screenX; + LinkDescriptionPopup.popupY = e.screenY - 100; + LinkDescriptionPopup.descriptionPopup = true; - }); + setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500); } } } - })); + }))); } - - @action @undoBatch - finishLinkClick = (screenX: number, screenY: number) => { + finishLinkClick = undoBatch(action((screenX: number, screenY: number) => { if (DocumentLinksButton.StartLink === this.props.View) { DocumentLinksButton.StartLink = undefined; - } else { - if (this.props.InMenu && !!!this.props.StartLink) { - if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) { - const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); - // this notifies any of the subviews that a document is made so that they can make finer-grained hyperlinks (). see note above in onLInkButtonMoved - runInAction(() => DocumentLinksButton.StartLink!._link = this.props.View._link = linkDoc); - setTimeout(action(() => DocumentLinksButton.StartLink!._link = this.props.View._link = undefined), 0); - LinkManager.currentLink = linkDoc; - - runInAction(() => { - if (linkDoc) { - TaskCompletionBox.textDisplayed = "Link Created"; - TaskCompletionBox.popupX = screenX; - TaskCompletionBox.popupY = screenY - 133; - TaskCompletionBox.taskCompleted = true; - - if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) { - LinkDescriptionPopup.popupX = screenX; - LinkDescriptionPopup.popupY = screenY - 100; - LinkDescriptionPopup.descriptionPopup = true; - } - - setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500); - } - }); + } else if (this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View) { + const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); + // this notifies any of the subviews that a document is made so that they can make finer-grained hyperlinks (). see note above in onLInkButtonMoved + DocumentLinksButton.StartLink!._link = this.props.View._link = linkDoc; + setTimeout(action(() => DocumentLinksButton.StartLink!._link = this.props.View._link = undefined), 0); + LinkManager.currentLink = linkDoc; + if (linkDoc) { + TaskCompletionBox.textDisplayed = "Link Created"; + TaskCompletionBox.popupX = screenX; + TaskCompletionBox.popupY = screenY - 133; + TaskCompletionBox.taskCompleted = true; + + if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) { + LinkDescriptionPopup.popupX = screenX; + LinkDescriptionPopup.popupY = screenY - 100; + LinkDescriptionPopup.descriptionPopup = true; } + + setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500); } } - } + })); @observable public static EditLink: DocumentView | undefined; public static EditLinkLoc: number[] = [0, 0]; + + @action clearLinks() { + DocumentLinksButton.StartLink = undefined; + } + @computed get linkButton() { TraceMobx(); @@ -205,18 +202,26 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp link : links.length} </div> - {DocumentLinksButton.StartLink && this.props.InMenu && !!!this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} - style={{ width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px" }} - onPointerDown={this.completeLink} onClick={e => this.finishLinkClick(e.screenX, e.screenY)} /> : (null)} + {DocumentLinksButton.StartLink && this.props.InMenu && !this.props.StartLink && + DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} + style={{ + width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px", + backgroundColor: DocumentLinksButton.StartLink ? "" : "grey", + border: DocumentLinksButton.StartLink ? "" : "none" + }} + onPointerDown={DocumentLinksButton.StartLink ? this.completeLink : emptyFunction} + onClick={e => DocumentLinksButton.StartLink ? this.finishLinkClick(e.screenX, e.screenY) : emptyFunction} /> : (null)} {DocumentLinksButton.StartLink === this.props.View && this.props.InMenu && this.props.StartLink ? <div className={"documentLinksButton-startLink"} - style={{ width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px" }} /> : (null)} + style={{ width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px" }} + onPointerDown={this.clearLinks} onClick={this.clearLinks} + /> : (null)} </div>; return (!links.length) && !this.props.AlwaysOn ? (null) : this.props.InMenu ? <Tooltip title={<><div className="dash-tooltip">{title}</div></>}> {linkButton} - </Tooltip> : !!!DocumentLinksButton.EditLink ? + </Tooltip> : !!!DocumentLinksButton.EditLink && !this.props.InMenu ? <Tooltip title={<><div className="dash-tooltip">{title}</div></>}> {linkButton} </Tooltip> : diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index b978f6245..e6b8928d4 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -54,6 +54,15 @@ } } + .documentView-anchorCont { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: inline-block; + } + .documentView-lock { width: 20; height: 20; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 22a2bb8fe..e6e709621 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -677,10 +677,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu @action onCopy = () => { - const copy = Doc.MakeCopy(this.props.Document, true); - copy.x = NumCast(this.props.Document.x) + NumCast(this.props.Document._width); - copy.y = NumCast(this.props.Document.y) + 30; - this.props.addDocument?.(copy); + const alias = Doc.MakeAlias(this.props.Document); + alias.x = NumCast(this.props.Document.x) + NumCast(this.props.Document._width); + alias.y = NumCast(this.props.Document.y) + 30; + this.props.addDocument?.(alias); } @action @@ -760,6 +760,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu moreItems.push({ description: "Write Back Link to Album", event: () => GooglePhotos.Transactions.AddTextEnrichment(this.props.Document), icon: "caret-square-right" }); } moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" }); + Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()) && moreItems.push({ description: "Toggle Always Show Link End", event: () => Doc.UserDoc()["documentLinksButton-hideEnd"] = !Doc.UserDoc()["documentLinksButton-hideEnd"], icon: "eye" }); } //GetEffectiveAcl(this.props.Document) === AclEdit && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" }); @@ -890,7 +891,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView ? (null) : // view that are not registered DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => - <DocumentView {...this.props} key={i + 1} + <div className="documentView-anchorCont" key={i + 1}> <DocumentView {...this.props} Document={d} ContainingCollectionView={this.props.ContainingCollectionView} ContainingCollectionDoc={this.props.Document} // bcz: hack this.props.Document is not a collection Need a better prop for passing the containing document to the LinkAnchorBox @@ -903,7 +904,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu pointerEvents={false} LayoutTemplate={undefined} LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(d, this.props.Document)}`)} - />); + /></div >); } @computed get innards() { TraceMobx(); diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss index 13af511a6..5bdafd857 100644 --- a/src/client/views/nodes/FontIconBox.scss +++ b/src/client/views/nodes/FontIconBox.scss @@ -1,77 +1,62 @@ -.fontIconBox-outerDiv { +.fontIconBox-label { + color: white; + margin-right: 4px; + margin-top: 1px; + position: relative; + text-align: center; + font-size: 7px; + letter-spacing: normal; + background-color: inherit; + border-radius: 8px; + margin-top: -8px; + padding: 0; width: 100%; - height: 100%; - pointer-events: all; - touch-action: none; - border-radius: inherit; - background: black; +} + +.menuButton-round { border-radius: 100%; - transform-origin: top left; .fontIconBox-label { - background: gray; - color: white; - border-radius: 8px; - width: 100%; + margin-left: -10px; // button padding is 10px; + bottom: 0; position: absolute; - text-align: center; - font-size: 8px; - //margin-top:4px; - letter-spacing: normal; - left: 0; - overflow: hidden; } +} - svg { - width: 95% !important; - height: 95%; +.menuButton-square { + padding-top: 3px; + padding-bottom: 3px; + padding-left: 5px; + + .fontIconBox-label { + border-radius: 0px; + margin-top: 0px; + border-radius: "inherit"; } } -.menuButton { - //padding: 7px; - padding-left: 5px; +.menuButton, +.menuButton-round, +.menuButton-square { width: 100%; - width: 60px; - height: 70px; - padding-top: 3px; - padding-bottom: 3px; + height: 100%; + pointer-events: all; + touch-action: none; .menuButton-wrap { - width: 45px; - /* padding: 5px; */ touch-action: none; - background: black; - transform-origin: top left; - /* margin-bottom: 5px; */ - margin-top: 5px; - margin-right: 25px; border-radius: 8px; - &:hover { - background: rgb(61, 61, 61); - cursor: pointer; - } - } - - .menuButton-label { - color: white; - margin-right: 4px; - border-radius: 8px; - width: 42px; - position: relative; - text-align: center; - font-size: 7px; - margin-top: 1px; - letter-spacing: normal; - padding: 3px; - background-color: inherit; + // &:hover { + // background: rgb(61, 61, 61); + // cursor: pointer; + // } } - .menuButton-icon { + .menuButton-icon-square { width: auto; height: 32px; - padding: 5px; + padding: 4px; } svg { diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 720d6a15d..eff5a4160 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -6,14 +6,12 @@ import { DocComponent } from '../DocComponent'; import './FontIconBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; import { StrCast, Cast, NumCast } from '../../../fields/Types'; -import { Utils } from "../../../Utils"; +import { Utils, emptyFunction } from "../../../Utils"; import { runInAction, observable, reaction, IReactionDisposer } from 'mobx'; import { Doc } from '../../../fields/Doc'; import { ContextMenu } from '../ContextMenu'; import { ScriptField } from '../../../fields/ScriptField'; import { Tooltip } from '@material-ui/core'; -import { createUnionOrIntersectionTypeNode } from 'typescript'; -import { CurrentUserUtils } from '../../util/CurrentUserUtils'; const FontIconSchema = createSchema({ icon: "string", }); @@ -61,45 +59,23 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>( } render() { - - //style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }}> - - if (this.layoutDoc.menuIcon) { - - let backgroundColor = "black"; - if (this.dataDoc.title === "Sharing" || this.dataDoc.title === "Help" || this.dataDoc.title === "Settings" || this.dataDoc.title === "Import") { - backgroundColor = "black"; - } else { - backgroundColor = CurrentUserUtils.selectedPanel === this.dataDoc.title ? "lightgrey" : "black"; - } - - const color = backgroundColor === "lightgrey" ? "black" : "white"; - const menuBTN = <div className="menuButton" style={{ backgroundColor: backgroundColor }}> - - <div className="menuButton-wrap" style={{ backgroundColor: backgroundColor }}> - <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" /> - <div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div> + const label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); + const color = StrCast(this.layoutDoc.color, this._foregroundColor); + const backgroundColor = StrCast(this.layoutDoc._backgroundColor, StrCast(this.rootDoc.backgroundColor, this.props.backgroundColor?.(this.rootDoc))); + const shape = StrCast(this.layoutDoc.iconShape, "round"); + const button = <> + <button className={`menuButton-${shape}`} ref={this._ref} onContextMenu={this.specificContextMenu} + style={{ boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined, backgroundColor }}> + <div className="menuButton-wrap"> + {<FontAwesomeIcon className={`menuButton-icon-${shape}`} icon={StrCast(this.dataDoc.icon, "user") as any} color={color} + size={this.layoutDoc.iconShape === "square" ? "sm" : "lg"} />} + {!label ? (null) : <div className="fontIconBox-label" style={{ color, backgroundColor }}> {label} </div>} </div> - </div>; - - return menuBTN; - } else { - const referenceDoc = (this.layoutDoc.dragFactory instanceof Doc ? this.layoutDoc.dragFactory : this.layoutDoc); - const refLayout = Doc.Layout(referenceDoc); - const button = <button className="fontIconBox-outerDiv" ref={this._ref} onContextMenu={this.specificContextMenu} - style={{ - padding: Cast(this.layoutDoc._xPadding, "number", null), - background: StrCast(refLayout._backgroundColor, StrCast(refLayout.backgroundColor)), - boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined - }}> - <FontAwesomeIcon className="fontIconBox-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={StrCast(this.layoutDoc.color, this._foregroundColor)} size="sm" /> - {!this.rootDoc.title ? (null) : <div className="fontIconBox-label" style={{ width: this.rootDoc.label ? "max-content" : undefined }}> {StrCast(this.rootDoc.label, StrCast(this.rootDoc.title).substring(0, 6))} </div>} - </button>; - return !this.layoutDoc.toolTip ? button : - <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}> - {button} - </Tooltip>; - } - + </button> + </>; + return !this.layoutDoc.toolTip ? button : + <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}> + {button} + </Tooltip>; } }
\ No newline at end of file diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 0dfbdc5cf..05ba6628c 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -41,7 +41,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument }, icon: "trash" }); - ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "mouse-pointer" }); } @undoBatch diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index d8fe47f4e..720af6c9d 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -19,12 +19,15 @@ export class LinkDescriptionPopup extends React.Component<{}> { @action descriptionChanged = (e: React.ChangeEvent<HTMLInputElement>) => { - LinkManager.currentLink && (LinkManager.currentLink.description = e.currentTarget.value); + this.description = e.currentTarget.value; } @action - onDismiss = () => { + onDismiss = (add: boolean) => { LinkDescriptionPopup.descriptionPopup = false; + if (add) { + LinkManager.currentLink && (LinkManager.currentLink.description = this.description); + } } @action @@ -50,15 +53,16 @@ export class LinkDescriptionPopup extends React.Component<{}> { left: LinkDescriptionPopup.popupX ? LinkDescriptionPopup.popupX : 700, top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350, }}> - <input className="linkDescriptionPopup-input" onKeyPress={e => e.key === "Enter" && this.onDismiss()} + <input className="linkDescriptionPopup-input" + onKeyPress={e => e.key === "Enter" && this.onDismiss(true)} placeholder={"(optional) enter link label..."} onChange={(e) => this.descriptionChanged(e)}> </input> <div className="linkDescriptionPopup-btn"> <div className="linkDescriptionPopup-btn-dismiss" - onPointerDown={this.onDismiss}> Dismiss </div> + onPointerDown={e => this.onDismiss(false)}> Dismiss </div> <div className="linkDescriptionPopup-btn-add" - onPointerDown={this.onDismiss}> Add </div> + onPointerDown={e => this.onDismiss(true)}> Add </div> </div> </div>; } diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index f76707a79..6e268be48 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -185,11 +185,15 @@ export default class RichTextMenu extends AntimodeMenu { const active = this.getActiveFontStylesOnSelection(); const activeFamilies = active.activeFamilies; const activeSizes = active.activeSizes; + const activeColors = active.activeColors; + const activeHighlights = active.activeHighlights; this.activeListType = this.getActiveListStyle(); this.activeAlignment = this.getActiveAlignment(); this.activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; this.activeFontSize = !activeSizes.length ? "13pt" : activeSizes.length === 1 ? String(activeSizes[0]) : "..."; + this.activeFontColor = !activeColors.length ? "black" : activeColors.length === 1 ? String(activeColors[0]) : "..."; + this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length === 1 ? String(activeHighlights[0]) : "..."; // update link in current selection const targetTitle = await this.getTextLinkTargetTitle(); @@ -250,10 +254,12 @@ export default class RichTextMenu extends AntimodeMenu { // finds font sizes and families in selection getActiveFontStylesOnSelection() { - if (!this.view) return { activeFamilies: [], activeSizes: [] }; + if (!this.view) return { activeFamilies: [], activeSizes: [], activeColors: [], activeHighlights: [] }; const activeFamilies: string[] = []; const activeSizes: string[] = []; + const activeColors: string[] = []; + const activeHighlights: string[] = []; if (this.TextView.props.isSelected(true)) { const state = this.view.state; const pos = this.view.state.selection.$from; @@ -261,15 +267,20 @@ export default class RichTextMenu extends AntimodeMenu { if (ref_node && ref_node !== this.view.state.doc && ref_node.isText) { ref_node.marks.forEach(m => { m.type === state.schema.marks.pFontFamily && activeFamilies.push(m.attrs.family); + m.type === state.schema.marks.pFontColor && activeColors.push(m.attrs.color); m.type === state.schema.marks.pFontSize && activeSizes.push(String(m.attrs.fontSize) + "pt"); + m.type === state.schema.marks.marker && activeHighlights.push(String(m.attrs.highlight)); }); } !activeFamilies.length && (activeFamilies.push(StrCast(this.TextView.layoutDoc._fontFamily, StrCast(Doc.UserDoc().fontFamily)))); !activeSizes.length && (activeSizes.push(StrCast(this.TextView.layoutDoc._fontSize, StrCast(Doc.UserDoc().fontSize)))); + !activeColors.length && (activeSizes.push(StrCast(this.TextView.layoutDoc.color, StrCast(Doc.UserDoc().fontColor)))); } !activeFamilies.length && (activeFamilies.push(StrCast(Doc.UserDoc().fontFamily))); !activeSizes.length && (activeSizes.push(StrCast(Doc.UserDoc().fontSize))); - return { activeFamilies, activeSizes }; + !activeColors.length && (activeColors.push(StrCast(Doc.UserDoc().fontColor, "black"))); + !activeHighlights.length && (activeHighlights.push(StrCast(Doc.UserDoc().fontHighlight, ""))); + return { activeFamilies, activeSizes, activeColors, activeHighlights }; } getMarksInSelection(state: EditorState<any>) { @@ -426,10 +437,16 @@ export default class RichTextMenu extends AntimodeMenu { } changeFontSize = (mark: Mark, view: EditorView) => { + if ((this.view?.state.selection.$from.pos || 0) < 2) { + this.TextView.layoutDoc._fontSize = mark.attrs.fontSize; + } this.setMark(view.state.schema.marks.pFontSize.create({ fontSize: mark.attrs.fontSize }), view.state, view.dispatch, true); } changeFontFamily = (mark: Mark, view: EditorView) => { + if ((this.view?.state.selection.$from.pos || 0) < 2) { + this.TextView.layoutDoc._fontFamily = mark.attrs.family; + } this.setMark(view.state.schema.marks.pFontFamily.create({ family: mark.attrs.family }), view.state, view.dispatch, true); } @@ -606,8 +623,11 @@ export default class RichTextMenu extends AntimodeMenu { label = "No marks are currently stored"; } + //onPointerDown={onBrushClick} + const button = <Tooltip title={<div className="dash-tooltip">style brush</div>} placement="bottom"> - <button className="antimodeMenu-button" onPointerDown={onBrushClick} style={this.brushMarks?.size > 0 ? { backgroundColor: "121212" } : {}}> + + <button className="antimodeMenu-button" style={this.brushMarks?.size > 0 ? { backgroundColor: "121212" } : {}}> <FontAwesomeIcon icon="paint-roller" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.brushMarks?.size > 0 ? 45 : 0}deg)` }} /> </button> </Tooltip>; @@ -616,11 +636,11 @@ export default class RichTextMenu extends AntimodeMenu { <div className="dropdown"> <p>{label}</p> <button onPointerDown={this.clearBrush}>Clear brush</button> - <input placeholder="-brush name-" ref={this._brushNameRef} onKeyPress={this.onBrushNameKeyPress}></input> + <input placeholder="-brush name-" ref={this._brushNameRef} onKeyPress={this.onBrushNameKeyPress} /> </div>; return ( - <ButtonDropdown view={this.view} key={"brush dropdown"} button={button} dropdownContent={dropdownContent} /> + <ButtonDropdown view={this.view} key={"brush dropdown"} button={button} dropdownContent={dropdownContent} openDropdownOnButton={true} /> ); } @@ -679,8 +699,9 @@ export default class RichTextMenu extends AntimodeMenu { self.TextView.EditorView!.focus(); } + // onPointerDown={onColorClick} const button = <Tooltip title={<div className="dash-tooltip">set font color</div>} placement="bottom"> - <button className="antimodeMenu-button color-preview-button" onPointerDown={onColorClick}> + <button className="antimodeMenu-button color-preview-button"> <FontAwesomeIcon icon="palette" size="lg" /> <div className="color-preview" style={{ backgroundColor: this.activeFontColor }}></div> </button> @@ -701,7 +722,7 @@ export default class RichTextMenu extends AntimodeMenu { </div>; return ( - <ButtonDropdown view={this.view} key={"color dropdown"} button={button} dropdownContent={dropdownContent} /> + <ButtonDropdown view={this.view} key={"color dropdown"} button={button} dropdownContent={dropdownContent} openDropdownOnButton={true} /> ); } @@ -733,8 +754,9 @@ export default class RichTextMenu extends AntimodeMenu { UndoManager.RunInBatch(() => self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch), "rt highlighter"); } + //onPointerDown={onHighlightClick} const button = <Tooltip title={<div className="dash-tooltip">set highlight color</div>} placement="bottom"> - <button className="antimodeMenu-button color-preview-button" key="highilghter-button" onPointerDown={onHighlightClick}> + <button className="antimodeMenu-button color-preview-button" key="highilghter-button" > <FontAwesomeIcon icon="highlighter" size="lg" /> <div className="color-preview" style={{ backgroundColor: this.activeHighlightColor }}></div> </button> @@ -755,7 +777,7 @@ export default class RichTextMenu extends AntimodeMenu { </div>; return ( - <ButtonDropdown view={this.view} key={"highlighter"} button={button} dropdownContent={dropdownContent} /> + <ButtonDropdown view={this.view} key={"highlighter"} button={button} dropdownContent={dropdownContent} openDropdownOnButton={true} /> ); } @@ -778,7 +800,9 @@ export default class RichTextMenu extends AntimodeMenu { const link = this.currentLink ? this.currentLink : ""; const button = <Tooltip title={<div className="dash-tooltip">set hyperlink</div>} placement="bottom"> - <div><FontAwesomeIcon icon="link" size="lg" /> </div> + <button className="antimodeMenu-button color-preview-button"> + <FontAwesomeIcon icon="link" size="lg" /> + </button> </Tooltip>; const dropdownContent = @@ -790,7 +814,8 @@ export default class RichTextMenu extends AntimodeMenu { <button className="remove-button" onPointerDown={e => this.deleteLink()}>Remove link</button> </div>; - return <ButtonDropdown view={this.view} key={"link button"} button={button} dropdownContent={dropdownContent} openDropdownOnButton={true} />; + return <ButtonDropdown view={this.view} key={"link button"} button={button} dropdownContent={dropdownContent} + openDropdownOnButton={true} link={true} />; } async getTextLinkTargetTitle() { @@ -877,10 +902,11 @@ export default class RichTextMenu extends AntimodeMenu { if (pos.nodeBefore !== null && pos.nodeBefore !== undefined) { ref_node = pos.nodeBefore; } - else if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) { - ref_node = pos.nodeAfter; + if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) { + if (!pos.nodeBefore || this.view.state.selection.$from.pos !== this.view.state.selection.$to.pos) + ref_node = pos.nodeAfter; } - else if (pos.pos > 0) { + if (!ref_node && pos.pos > 0) { let skip = false; for (let i: number = pos.pos - 1; i > 0; i--) { this.view.state.doc.nodesBetween(i, pos.pos, (node: ProsNode) => { @@ -989,6 +1015,7 @@ interface ButtonDropdownProps { button: JSX.Element; dropdownContent: JSX.Element; openDropdownOnButton?: boolean; + link?: boolean; } @observer @@ -1031,18 +1058,10 @@ export class ButtonDropdown extends React.Component<ButtonDropdownProps> { render() { return ( <div className="button-dropdown-wrapper" ref={node => this.ref = node}> - {this.props.openDropdownOnButton ? - <button className="antimodeMenu-button dropdown-button-combined" onPointerDown={this.onDropdownClick}> - {this.props.button} - <FontAwesomeIcon icon="caret-down" size="sm" /> - </button> : - <> - {this.props.button} - <button className="dropdown-button antimodeMenu-button" key="antimodebutton" onPointerDown={this.onDropdownClick}> - <FontAwesomeIcon icon="caret-down" size="sm" /> - </button> - </>} - + <div className="antimodeMenu-button dropdown-button-combined" onPointerDown={this.onDropdownClick}> + {this.props.button} + <div style={{ marginTop: "-8.5" }}><FontAwesomeIcon icon="caret-down" size="sm" /></div> + </div> {this.showDropdown ? this.props.dropdownContent : (null)} </div> ); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 85fc63074..9cd7eaa69 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -409,7 +409,7 @@ export namespace Doc { // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype'). export function GetProto(doc: Doc): Doc { if (doc instanceof Promise) { - console.log("GetProto: error: got Promise insead of Doc"); + console.log("GetProto: warning: got Promise insead of Doc"); } const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc)); return proto === doc ? proto : Doc.GetProto(proto); diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 5cf0e0cc3..2ca5ac082 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -20,7 +20,7 @@ export class RichTextField extends ObjectField { } Empty() { - return !(this.Text || this.Data.toString().includes("dashField")); + return !(this.Text || this.Data.toString().includes("dashField") || this.Data.toString().includes("align")); } [Copy]() { diff --git a/src/fields/util.ts b/src/fields/util.ts index 957b2c8cd..44a3317db 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -10,7 +10,6 @@ import { DocServer } from "../client/DocServer"; import { ComputedField } from "./ScriptField"; import { ScriptCast, StrCast } from "./Types"; import { returnZero } from "../Utils"; -import { addSyntheticLeadingComment } from "typescript"; function _readOnlySetter(): never { diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx index b75102e43..8ae504f1b 100644 --- a/src/mobile/AudioUpload.tsx +++ b/src/mobile/AudioUpload.tsx @@ -53,7 +53,7 @@ export class AudioUpload extends React.Component { * Pushing the audio doc onto Dash Web through the right side bar */ uploadAudio = () => { - const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; + const audioRightSidebar = Cast(Doc.UserDoc()["sidebar-sharing"], Doc) as Doc; const audioDoc = this._audioCol; const data = Cast(audioRightSidebar.data, listSpec(Doc)); for (let i = 1; i < 8; i++) { diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 3a889b0db..40aa65372 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -436,7 +436,7 @@ export class MobileInterface extends React.Component { // DocButton that uses UndoManager and handles the opacity change if CanUndo is true @computed get undo() { if (this.mainContainer && this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && - this._activeDoc !== Doc.UserDoc().rightSidebarCollection && this._activeDoc.title !== "WORKSPACES") { + this._activeDoc !== Doc.UserDoc()["sidebar-sharing"] && this._activeDoc.title !== "WORKSPACES") { return ( <div className="docButton" style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanUndo() ? "1" : "0.4", }} @@ -454,7 +454,7 @@ export class MobileInterface extends React.Component { // DocButton that uses UndoManager and handles the opacity change if CanRedo is true @computed get redo() { if (this.mainContainer && this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && - this._activeDoc !== Doc.UserDoc().rightSidebarCollection && this._activeDoc.title !== "WORKSPACES") { + this._activeDoc !== Doc.UserDoc()["sidebar-sharing"] && this._activeDoc.title !== "WORKSPACES") { return ( <div className="docButton" style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanRedo() ? "1" : "0.4", }} @@ -605,7 +605,7 @@ export class MobileInterface extends React.Component { // Returns the image upload pop up @computed get uploadImage() { - const doc = !this._homeMenu ? this._activeDoc : Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; + const doc = !this._homeMenu ? this._activeDoc : Cast(Doc.UserDoc()["sidebar-sharing"], Doc) as Doc; return <Uploader Document={doc} />; } @@ -628,7 +628,7 @@ export class MobileInterface extends React.Component { */ @action switchToMobileUploads = () => { - const mobileUpload = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; + const mobileUpload = Cast(Doc.UserDoc()["sidebar-sharing"], Doc) as Doc; this.switchCurrentView(mobileUpload); this._homeMenu = false; } diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 827888ff7..d81450b32 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -208,12 +208,12 @@ export namespace WebSocket { } function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { - process.stdout.write(`(f)`) + process.stdout.write(`.`); Database.Instance.getDocument(id, callback); } function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) { - console.log(green(`> ${ids.length} fields`)); + process.stdout.write(`${ids.length}…`); Database.Instance.getDocuments(ids, callback); } |