diff options
Diffstat (limited to 'src/client')
39 files changed, 689 insertions, 585 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index fa1fca6ff..ba59a9f50 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -64,7 +64,7 @@ export namespace DocServer { } export let _socket: SocketIOClient.Socket; // this client's distinct GUID created at initialization - let GUID: string; + let USER_ID: string; // indicates whether or not a document is currently being udpated, and, if so, its id export enum WriteMode { @@ -154,7 +154,7 @@ export namespace DocServer { export function init(protocol: string, hostname: string, port: number, identifier: string) { _cache = {}; - GUID = identifier; + USER_ID = identifier; protocol = protocol.startsWith('https') ? 'wss' : 'ws'; _socket = io.connect(`${protocol}://${hostname}:${port}`); // io.connect(`https://7f079dda.ngrok.io`);// if using ngrok, create a special address for the websocket @@ -228,7 +228,7 @@ export namespace DocServer { * indicating that this client has connected */ function onConnection() { - _socket.emit(MessageStore.Bar.Message, GUID); + _socket.emit(MessageStore.Bar.Message, USER_ID); } export namespace Util { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e8947f190..2e4fb0f1c 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -343,15 +343,15 @@ export class CurrentUserUtils { const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails"; return [ - { title: "Dashboards", toolTip: "Dashboards ⌘D", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} }, - { title: "Search", toolTip: "Search ⌘F", target: this.setupSearcher(doc, "mySearcher"), ignoreClick: true, icon: "search", }, - { title: "Files", toolTip: "Files ⌘⇧F", target: this.setupFilesystem(doc, "myFilesystem"), ignoreClick: true, icon: "folder-open", }, - { title: "Tools", toolTip: "Tools ⌘T", target: this.setupToolsBtnPanel(doc, "myTools"), ignoreClick: true, icon: "wrench", funcs: {hidden: "IsNoviceMode()"} }, - { title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), ignoreClick: true, icon: "upload", }, - { title: "Closed", toolTip: "Recently Closed ⌘R", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive", }, - { title: "Shared", toolTip: "Shared Docs ⌘⇧S", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, - { title: "Trails", toolTip: "Trails ⌘⇧", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, - { title: "User Doc", toolTip: "User Doc ⌘U", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, + { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} }, + { title: "Search", toolTip: "Search ⌘F", target: this.setupSearcher(doc, "mySearcher"), ignoreClick: true, icon: "search", }, + { title: "Files", toolTip: "Files", target: this.setupFilesystem(doc, "myFilesystem"), ignoreClick: true, icon: "folder-open", }, + { title: "Tools", toolTip: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), ignoreClick: true, icon: "wrench", funcs: {hidden: "IsNoviceMode()"} }, + { title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), ignoreClick: true, icon: "upload", }, + { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive", }, + { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, + { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, + { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(self)'}})); } @@ -602,7 +602,7 @@ export class CurrentUserUtils { const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet { scripts: { onClick: "undo()"}, opts: { title: "Undo", icon: "undo-alt", toolTip: "Undo ⌘Z" }}, - { scripts: { onClick: "redo()"}, opts: { title: "Redo", icon: "redo-alt", toolTip: "Redo ⌘R" }}, + { scripts: { onClick: "redo()"}, opts: { title: "Redo", icon: "redo-alt", toolTip: "Redo ⌘⇧Z" }}, { scripts: { }, opts: { title: "undoStack", layout: "<UndoStack>", toolTip: "Undo/Redo Stack"}}, // note: layout fields are hacks -- they don't actually run through the JSX parser (yet) { scripts: { }, opts: { title: "linker", layout: "<LinkingUI>", toolTip: "link started"}}, { scripts: { }, opts: { title: "currently playing", layout: "<CurrentlyPlayingUI>", toolTip: "currently playing media"}}, diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index b921b3116..8e4e0d8f3 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,10 +1,11 @@ import { action, computed, observable, ObservableSet } from 'mobx'; -import { Doc, Opt } from '../../fields/Doc'; -import { Animation } from '../../fields/DocSymbols'; +import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../fields/Types'; import { AudioField } from '../../fields/URLField'; +import { GetEffectiveAcl } from '../../fields/util'; import { CollectionViewType } from '../documents/DocumentTypes'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { TabDocView } from '../views/collections/TabDocView'; @@ -344,6 +345,9 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe }); } }; + if (Doc.IsDataProto(doc) && DocListCast(doc.proto_embeddings).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) { + doc = DocListCast(doc.proto_embeddings).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!; + } if (doc.hidden) { doc.hidden = false; options.toggleTarget = false; diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 253ed5d2a..673af16ee 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -7,33 +7,48 @@ .group-create { display: flex; flex-direction: column; - height: 90%; + overflow: visible; + height: 100%; + width: 98.5%; + padding: 5px; justify-content: space-between; margin-left: 5px; - input { - border-radius: 5px; - padding: 8px; - min-width: 100%; - border: 1px solid hsl(0, 0%, 80%); - outline: none; - height: 30; - - &:focus { - border: 2.5px solid #2684FF; - } - } - p { font-size: 20px; text-align: left; - color: black; } + } - button { - align-self: flex-end; + .group-input { + + input { + padding: 8px; + width: 100%; + outline: none; + border: none; + min-width: 100%; + border: 2px solid; + border-radius: 4px; + border-color: inherit; + background: white; + color: black; + height: 30; } } + + .select-users { + margin-right: 3; + max-height: 30; + width: 100%; + display: inline-flex; + flex-direction: row; + border: 2px solid; + border-radius: 4px; + border-color: inherit; + background: white; + color: black; + } } @@ -55,11 +70,14 @@ .group-interface { display: flex; flex-direction: column; + overflow: hidden; + padding: 10px; .overlay { transform: translate(-10px, -10px); width: 400px; height: 320px; + overflow: hidden; } .delete-button { @@ -81,7 +99,6 @@ font-size: 20px; text-align: left; margin-right: 15px; - color: black; } } @@ -94,18 +111,24 @@ margin-left: 5; width: 50px; cursor: pointer; + display: flex; + flex-direction: row; + } + + .style-divider { + width: 100%; + height: 1px; } .group-body { justify-content: space-between; - height: 220; - background-color: #e8e8e8; + height: 225; padding-right: 1em; justify-content: space-around; text-align: left; - overflow-y: auto; + overflow-y: hidden; width: 100%; .group-row { @@ -117,7 +140,6 @@ .group-name { max-width: 65%; margin: 0 10; - color: black; } .group-info { diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index da947aba6..5802d5ee0 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -15,6 +15,7 @@ import { SharingManager, User } from './SharingManager'; import { listSpec } from '../../fields/Schema'; import { DateField } from '../../fields/DateField'; import { Id } from '../../fields/FieldSymbols'; +import { Button, IconButton, Size } from 'browndash-components'; /** * Interface for options for the react-select component @@ -280,47 +281,59 @@ export class GroupManager extends React.Component<{}> { */ private get groupCreationModal() { const contents = ( - <div className="group-create"> + <div className="group-create" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}> <div className="group-heading" style={{ marginBottom: 0 }}> <p> <b>New Group</b> </p> - <div - className={'close-button'} - onClick={action(() => { - this.createGroupModalOpen = false; - TaskCompletionBox.taskCompleted = false; - })}> - <FontAwesomeIcon icon={'times'} color={'black'} size={'lg'} /> + <div className="close-button"> + <Button + icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} + onClick={action(() => { + this.createGroupModalOpen = false; + TaskCompletionBox.taskCompleted = false; + })} + color={StrCast(Doc.UserDoc().userColor)} + /> </div> </div> - <input className="group-input" ref={this.inputRef} onKeyDown={this.handleKeyDown} autoFocus type="text" placeholder="Group name" onChange={action(() => (this.buttonColour = this.inputRef.current?.value ? 'black' : '#979797'))} /> - <Select - isMulti - options={this.options} - onChange={this.handleChange} - placeholder={'Select users'} - value={this.selectedUsers} - closeMenuOnSelect={false} - styles={{ - dropdownIndicator: (base, state) => ({ - ...base, - transition: '0.5s all ease', - transform: state.selectProps.menuIsOpen ? 'rotate(180deg)' : undefined, - }), - multiValue: base => ({ - ...base, - maxWidth: '50%', - - '&:hover': { - maxWidth: 'unset', - }, - }), - }} - /> - <button ref={this.createGroupButtonRef} onClick={this.createGroup} style={{ background: this.buttonColour }} disabled={this.buttonColour === '#979797'}> - Create - </button> + <div className="group-input" style={{border: StrCast(Doc.UserDoc().userColor)}} > + <input ref={this.inputRef} onKeyDown={this.handleKeyDown} autoFocus type="text" placeholder="Group name" onChange={action(() => (this.buttonColour = this.inputRef.current?.value ? 'black' : '#979797'))} /> + </div> + <div style={{border: StrCast(Doc.UserDoc().userColor)}}> + <Select + className="select-users" + isMulti + options={this.options} + onChange={this.handleChange} + placeholder={'Select users'} + value={this.selectedUsers} + closeMenuOnSelect={false} + styles={{ + control: () => ({ + display: 'inline-flex', + width: '100%', + }), + indicatorSeparator: () => ({ + display: 'inline-flex', + visibility: 'hidden', + }), + indicatorsContainer: () => ({ + display: 'inline-flex', + textDecorationColor: 'black', + }), + valueContainer: () => ({ + display: 'inline-flex', + fontStyle: StrCast(Doc.UserDoc().userColor), + color: StrCast(Doc.UserDoc().userColor), + width: '100%', + }), + }} + /> + </div> + <div className={"create-button"}> + <Button text={"Create"} type={"tertiary"} color={StrCast(Doc.UserDoc().userColor)} onClick={this.createGroup} /> + </div> </div> ); @@ -353,37 +366,34 @@ export class GroupManager extends React.Component<{}> { const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups; return ( - <div className="group-interface"> + <div className="group-interface" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}> {this.groupCreationModal} {this.currentGroup ? <GroupMemberView group={this.currentGroup} onCloseButtonClick={action(() => (this.currentGroup = undefined))} /> : null} <div className="group-heading"> <p> <b>Manage Groups</b> </p> - <button onClick={action(() => (this.createGroupModalOpen = true))}> - <FontAwesomeIcon icon={'plus'} size={'sm'} /> Create Group - </button> - <div className={'close-button'} onClick={this.close}> - <FontAwesomeIcon icon={'times'} color={'black'} size={'lg'} /> + <Button icon={<FontAwesomeIcon icon={'plus'}/>} iconPlacement={'left'} text={"Create Group"} type={"tertiary"} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (this.createGroupModalOpen = true))} /> + <div className={'close-button'} > + <Button + icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} + onClick={this.close} + color={StrCast(Doc.UserDoc().userColor)} + /> </div> </div> <div className="main-container"> <div className="sort-groups" onClick={action(() => (this.groupSort = this.groupSort === 'ascending' ? 'descending' : this.groupSort === 'descending' ? 'none' : 'ascending'))}> - Name{' '} - {this.groupSort === 'ascending' ? ( - <FontAwesomeIcon icon={'caret-up'} size={'xs'} /> - ) : this.groupSort === 'descending' ? ( - <FontAwesomeIcon icon={'caret-down'} size={'xs'} /> - ) : ( - <FontAwesomeIcon icon={'caret-right'} size={'xs'} /> - )} + Name + <IconButton icon={<FontAwesomeIcon icon={this.groupSort === 'ascending' ? 'caret-up' : this.groupSort === 'descending' ? 'caret-down' : 'caret-right'}/>} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} /> </div> - <div className="group-body"> + <div className={'style-divider'} style={{background: StrCast(Doc.UserDoc().userColor)}}/> + <div className="group-body" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}> {groups.map(group => ( <div className="group-row" key={StrCast(group.title || group.groupName)}> <div className="group-name">{StrCast(group.title || group.groupName)}</div> <div className="group-info" onClick={action(() => (this.currentGroup = group))}> - <FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} /> + <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (this.currentGroup = group))} /> </div> </div> ))} diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss index 2eb164988..d50569b26 100644 --- a/src/client/util/GroupMemberView.scss +++ b/src/client/util/GroupMemberView.scss @@ -1,6 +1,9 @@ .editing-interface { width: 100%; height: 100%; + padding: 10px; + float: right; + overflow: visible; hr { margin-top: 20; @@ -10,7 +13,6 @@ outline: none; border-radius: 5px; border: 0px; - color: #fcfbf7; text-transform: none; letter-spacing: 2px; font-size: 75%; @@ -37,8 +39,6 @@ text-align: center; border: none; outline: none; - color: black; - margin-top: -5; height: 20; text-overflow: ellipsis; background: none; @@ -61,21 +61,36 @@ margin-bottom: 25; .add-member-dropdown { - width: 65%; - margin: 0 5; + margin-right: 3; + max-height: 30; + width: 250px; + display: inline-flex; + flex-direction: row; + border: 2px solid; + border-radius: 4px; + border-color: inherit; + background: white; + color: black; + } - input { - height: 30; - } + .delete-button { + align-self: center; + background: inherit; } } } + .style-divider { + width: 98%; + height: 1px; + margin-top: 20px; + margin-bottom: 20px; + } + .editing-contents { overflow-y: auto; height: 62%; width: 100%; - color: black; margin-top: -15px; .editing-row { diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index b7f89794d..f2050dc61 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -8,6 +8,7 @@ import { StrCast } from "../../fields/Types"; import { MainViewModal } from "../views/MainViewModal"; import { GroupManager, UserOptions } from "./GroupManager"; import "./GroupMemberView.scss"; +import { Button, IconButton, Size } from "browndash-components"; interface GroupMemberViewProps { group: Doc; @@ -28,7 +29,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> { const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group); return (!this.props.group ? null : - <div className="editing-interface"> + <div className="editing-interface" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}> <div className="editing-header"> <input className="group-title" @@ -38,28 +39,48 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> { disabled={!hasEditAccess} > </input> - <div className={"memberView-closeButton"} onClick={action(this.props.onCloseButtonClick)}> - <FontAwesomeIcon icon={"times"} color={"black"} size={"lg"} /> + <div className={"memberView-closeButton"} > + <Button + icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} + onClick={action(this.props.onCloseButtonClick)} + color={StrCast(Doc.UserDoc().userColor)} + /> </div> {GroupManager.Instance.hasEditAccess(this.props.group) ? <div className="group-buttons"> - <div className="add-member-dropdown"> - <Select + <div style={{border: StrCast(Doc.UserDoc().userColor)}} > + <Select + className="add-member-dropdown" isSearchable={true} options={options} onChange={selectedOption => GroupManager.Instance.addMemberToGroup(this.props.group, (selectedOption as UserOptions).value)} placeholder={"Add members"} value={null} styles={{ - dropdownIndicator: (base, state) => ({ - ...base, - transition: '0.5s all ease', - transform: state.selectProps.menuIsOpen ? 'rotate(180deg)' : undefined - }) + control: () => ({ + display: 'inline-flex', + width: '100%', + }), + indicatorSeparator: () => ({ + display: 'inline-flex', + visibility: 'hidden', + }), + indicatorsContainer: () => ({ + display: 'inline-flex', + textDecorationColor: 'black', + }), + valueContainer: () => ({ + display: 'inline-flex', + fontStyle: StrCast(Doc.UserDoc().userColor), + color: StrCast(Doc.UserDoc().userColor), + width: '100%', + }), }} /> </div> - <button onClick={() => GroupManager.Instance.deleteGroup(this.props.group)}>Delete group</button> + <div className={"delete-button"}> + <Button text={"Delete Group"} type={"tertiary"} color={StrCast(Doc.UserDoc().userColor)} onClick={() => GroupManager.Instance.deleteGroup(this.props.group)} /> + </div> </div> : null} <div @@ -69,7 +90,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> { Emails {this.memberSort === "ascending" ? "↑" : this.memberSort === "descending" ? "↓" : ""} {/* → */} </div> </div> - <hr /> + <div className={'style-divider'} style={{background: StrCast(Doc.UserDoc().userColor)}}/> <div className="editing-contents" style={{ height: hasEditAccess ? "62%" : "85%" }} > @@ -83,7 +104,7 @@ export class GroupMemberView extends React.Component<GroupMemberViewProps> { </div> {hasEditAccess ? <div className={"remove-button"} onClick={() => GroupManager.Instance.removeMemberFromGroup(this.props.group, member)}> - <FontAwesomeIcon icon={"trash-alt"} size={"sm"} /> + <IconButton icon={<FontAwesomeIcon icon={'trash-alt'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={() => GroupManager.Instance.removeMemberFromGroup(this.props.group, member)} /> </div> : null} </div> diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 043f0f1f3..d0f459291 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -178,7 +178,7 @@ export namespace InteractionUtils { filter: mask ? `url(#mask${defGuid})` : undefined, opacity: 1.0, // opacity: strokeWidth !== width ? 0.5 : undefined, - pointerEvents: pevents as any, + pointerEvents: (pevents as any) === 'all' ? 'visiblepainted' : (pevents as any), stroke: color ?? 'rgb(0, 0, 0)', strokeWidth: strokeWidth, strokeLinecap: lineCap as any, diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index b11e694ff..c9f86f0e1 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -2,10 +2,6 @@ width: 600px; // height: 360px; - .overlay { - transform: translate(-20px, -20px); - } - .select { text-align: justify; text-align-last: end @@ -33,12 +29,7 @@ } .share-copy-link { - display: inline; border-radius: 4px; - border: solid gray 1px; - font-size: x-small; - background: #E8E8E8; - color: black; margin-top: -15px; margin-bottom: 15px; width: fit-content; @@ -50,13 +41,22 @@ display: flex; margin-bottom: 20px; align-items: center; - height: 36; + max-height: 28; .user-search { + max-height: 30; width: 90%; + display: inline-flex; + flex-direction: row; + border: 2px solid; + border-radius: 4px; + border-color: inherit; + background: white; + color: black; input { - height: 30; + height: 20px; + width: 100px; } } @@ -68,14 +68,12 @@ text-align-last: end; font-size: 13px; min-width: 90px; - height: 36; + height: 28; margin-left: 2px; } .share-button { - height: 36; margin-left: 3%; - background-color: black; } } @@ -131,6 +129,7 @@ display: flex; top:0; flex-direction: column; + border-radius: 4px; .user-sort { text-align: left; @@ -147,11 +146,12 @@ .groups-list, .users-list { font-style: italic; - background: #e8e8e8; - border: 2px solid gray; + border: 2px solid; padding-left: 10px; padding-right: 10px; width: 97%; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; overflow-y: scroll; overflow-x: hidden; text-align: left; @@ -160,7 +160,6 @@ align-items: center; text-align: center; justify-content: center; - color: black; height: 250px; margin: 0 2; @@ -175,7 +174,6 @@ outline: none; border-radius: 5px; border: 0px; - color: #fcfbf7; text-transform: none; letter-spacing: 2px; font-size: 75%; @@ -194,11 +192,10 @@ font-size: 20px; text-align: left; margin: 0 0 20px 0; - color: black; } .hr-substitute { - border: solid black 0.5px; + border: solid 0.5px; margin-top: 20px; } @@ -223,11 +220,12 @@ height: 25px; padding-left: 2; width: 97%; + border-radius: 4px; margin-top: 10px; margin-left: -8px; font-size: 14; margin-bottom: -4; - border: 2px solid gray; + border: 2px solid; border-bottom: none; align-items: center; display: flex; @@ -237,11 +235,12 @@ height: 25px; padding-left: 2; width: 97%; + border-radius: 4px; margin-top: 10px; - margin-left: -.5px; + margin-left: -8px; font-size: 14; margin-bottom: -4; - border: 2px solid gray; + border: 2px solid; border-bottom: none; align-items: center; display: flex; @@ -264,7 +263,7 @@ font-weight: normal; padding: 3px; - border-bottom: 0.5px solid grey; + border-bottom: 0.5px solid; .group-info { cursor: pointer; @@ -368,35 +367,35 @@ margin-top: 20px; } - .link-container { - display: flex; - flex-direction: row; - margin-bottom: 10px; - margin-left: auto; - margin-right: auto; - - .link-box, - .copy { - padding: 10px; - border-radius: 10px; - padding: 10px; - border: solid black 1px; - } - - .link-box { - background: white; - color: blue; - text-decoration: underline; - } - - .copy { - margin-left: 20px; - cursor: alias; - border-radius: 50%; - width: 42px; - height: 42px; - transition: 1.5s all ease; - padding-top: 12px; - } - } + // .link-container { + // display: flex; + // flex-direction: row; + // margin-bottom: 10px; + // margin-left: auto; + // margin-right: auto; + + // .link-box, + // .copy { + // padding: 10px; + // border-radius: 10px; + // padding: 10px; + // border: solid black 1px; + // } + + // .link-box { + // background: white; + // color: blue; + // text-decoration: underline; + // } + + // .copy { + // margin-left: 20px; + // cursor: alias; + // border-radius: 50%; + // width: 42px; + // height: 42px; + // transition: 1.5s all ease; + // padding-top: 12px; + // } + // } }
\ No newline at end of file diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 33c9992d0..cadcb1f8a 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Colors } from 'browndash-components'; +import { Button, IconButton, Size, Type } from 'browndash-components'; import { concat, intersection } from 'lodash'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -80,7 +80,7 @@ export class SharingManager extends React.Component<{}> { @observable private showUserOptions: boolean = false; // whether to show individuals as options when sharing (in the react-select component) @observable private showGroupOptions: boolean = false; // // whether to show groups as options when sharing (in the react-select component) private populating: boolean = false; // whether the list of users is populating or not - @observable private overrideNested: boolean = false; // whether child docs in a collection/dashboard should be changed to be less private - initially selected so default is override + @observable private upgradeNested: boolean = false; // whether child docs in a collection/dashboard should be changed to be less private - initially selected so default is upgrade all @observable private layoutDocAcls: boolean = false; // whether the layout doc or data doc's acls are to be used @observable private myDocAcls: boolean = false; // whether the My Docs checkbox is selected or not @observable private _buttonDown = false; @@ -97,7 +97,7 @@ export class SharingManager extends React.Component<{}> { DictationOverlay.Instance.hasActiveModal = true; this.isOpen = this.targetDoc !== undefined; this.permissions = SharingPermissions.Augment; - this.overrideNested = true; + this.upgradeNested = true; }); }; @@ -162,7 +162,7 @@ export class SharingManager extends React.Component<{}> { const acl = `acl-${normalizeEmail(user.email)}`; const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.rootDoc); docs.map(doc => (this.layoutDocAcls || doc.dockingConfig ? doc : Doc.GetProto(doc))).forEach(doc => { - distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.overrideNested ? true : undefined); + distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.upgradeNested ? true : undefined); if (permission !== SharingPermissions.None) { Doc.AddDocToList(sharingDoc, doc.dockingConfig ? dashStorage : storage, doc); } else GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, ((doc.createdFrom as Doc) || doc).dockingConfig ? dashStorage : storage, (doc.createdFrom as Doc) || doc); @@ -180,7 +180,7 @@ export class SharingManager extends React.Component<{}> { const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.rootDoc); docs.map(doc => (this.layoutDocAcls || doc.dockingConfig ? doc : Doc.GetProto(doc))).forEach(doc => { - distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.overrideNested ? true : undefined); + distributeAcls(acl, permission as SharingPermissions, doc, undefined, this.upgradeNested ? true : undefined); if (group instanceof Doc) { Doc.AddDocToList(group, 'docsShared', doc); @@ -525,14 +525,10 @@ export class SharingManager extends React.Component<{}> { const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-'; return !permissions ? null : ( - <div key={groupKey} className={'container'}> + <div key={groupKey} className={'container'} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }}> <div className={'padding'}>{StrCast(group.title)}</div> - {group instanceof Doc ? ( - <div className="group-info" onClick={action(() => (GroupManager.Instance.currentGroup = group))}> - <FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} /> - </div> - ) : null} + {group instanceof Doc ? <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null} <div className={'edit-actions'}> {admin || this.myDocAcls ? ( <select className={`permissions-dropdown-${permissions}`} value={permissions} onChange={e => this.setInternalGroupSharing(group, e.currentTarget.value)}> @@ -551,34 +547,28 @@ export class SharingManager extends React.Component<{}> { return ( <div className="sharing-interface"> {GroupManager.Instance?.currentGroup ? <GroupMemberView group={GroupManager.Instance.currentGroup} onCloseButtonClick={action(() => (GroupManager.Instance.currentGroup = undefined))} /> : null} - <div className="sharing-contents" + <div + className="sharing-contents" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), - color: StrCast(Doc.UserDoc().userColor) - }} - > - <p className="share-title"> - <div className="share-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')}> - <FontAwesomeIcon icon={'question-circle'} size={'sm'} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties/sharing-and-permissions/', '_blank')} /> + color: StrCast(Doc.UserDoc().userColor), + }}> + <p className="share-title" style={{ color: StrCast(Doc.UserDoc().userColor) }}> + <div className="share-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/collaboration/', '_blank')}> + <FontAwesomeIcon icon={'question-circle'} size={'sm'} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/collaboration/', '_blank')} /> </div> <b>Share </b> {this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')} </p> - <button - className="share-copy-link" - style={{ background: this._buttonDown ? Colors.LIGHT_BLUE : undefined }} - onPointerDown={action(e => (this._buttonDown = true))} - onPointerUp={action(e => (this._buttonDown = false))} - onClick={this.copyURL}> - <FontAwesomeIcon title="Copy Public URL" icon="copy" size="sm" /> - Copy Public URL - </button> - <div className="close-button" onClick={this.close}> - <FontAwesomeIcon icon="times" color="black" size="lg" /> + <div className="share-copy-link"> + <Button type={Type.TERT} color={StrCast(Doc.UserDoc().userColor)} icon={<FontAwesomeIcon icon={'copy'} size="sm" />} iconPlacement={'left'} text={'Copy Guest URL'} onClick={this.copyURL} /> + </div> + <div className="close-button"> + <Button icon={<FontAwesomeIcon icon={'times'} size={'lg'} />} onClick={this.close} color={StrCast(Doc.UserDoc().userColor)} /> </div> {admin ? ( <div className="share-container"> - <div className="share-setup"> + <div className="share-setup" style={{ border: StrCast(Doc.UserDoc().userColor) }}> <Select className="user-search" placeholder="Enter user or group name..." @@ -590,9 +580,24 @@ export class SharingManager extends React.Component<{}> { onChange={this.handleUsersChange} value={this.selectedUsers} styles={{ + control: () => ({ + display: 'inline-flex', + width: '100%', + }), indicatorSeparator: () => ({ + display: 'inline-flex', visibility: 'hidden', }), + indicatorsContainer: () => ({ + display: 'inline-flex', + textDecorationColor: 'black', + }), + valueContainer: () => ({ + display: 'inline-flex', + fontStyle: StrCast(Doc.UserDoc().userColor), + color: StrCast(Doc.UserDoc().userColor), + width: '100%', + }), }} /> <div className="permissions-select"> @@ -600,9 +605,9 @@ export class SharingManager extends React.Component<{}> { {this.sharingOptions(true)} </select> </div> - <button ref={this.shareDocumentButtonRef} className="share-button" onClick={this.share}> - Share - </button> + <div className="share-button"> + <Button text={'SHARE'} type={Type.TERT} color={StrCast(Doc.UserDoc().userColor)} onClick={this.share} /> + </div> </div> <div className="sort-checkboxes"> <input type="checkbox" onChange={action(() => (this.showUserOptions = !this.showUserOptions))} /> <label style={{ marginRight: 10 }}>Individuals</label> @@ -612,7 +617,7 @@ export class SharingManager extends React.Component<{}> { <div className="acl-container"> {Doc.noviceMode ? null : ( <div className="layoutDoc-acls"> - <input type="checkbox" onChange={action(() => (this.overrideNested = !this.overrideNested))} checked={this.overrideNested} /> <label>Override Nested </label> + <input type="checkbox" onChange={action(() => (this.upgradeNested = !this.upgradeNested))} checked={this.upgradeNested} /> <label>Upgrade Nested </label> <input type="checkbox" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> <label>Layout</label> </div> )} @@ -627,12 +632,16 @@ export class SharingManager extends React.Component<{}> { </div> </div> )} - <div className="main-container"> + <div className="main-container" style={{ color: StrCast(Doc.UserDoc().userColor), border: StrCast(Doc.UserDoc().userColor) }}> <div className={'individual-container'}> <div className="user-sort" onClick={action(() => (this.individualSort = this.individualSort === 'ascending' ? 'descending' : this.individualSort === 'descending' ? 'none' : 'ascending'))}> <div className="title-individual"> - Individuals - <FontAwesomeIcon icon={this.individualSort === 'ascending' ? 'caret-up' : this.individualSort === 'descending' ? 'caret-down' : 'caret-right'} size="xs" /> + Individuals + <IconButton + icon={<FontAwesomeIcon icon={this.individualSort === 'ascending' ? 'caret-up' : this.individualSort === 'descending' ? 'caret-down' : 'caret-right'} />} + size={Size.XSMALL} + color={StrCast(Doc.UserDoc().userColor)} + /> </div> </div> <div className="users-list">{userListContents}</div> @@ -640,12 +649,13 @@ export class SharingManager extends React.Component<{}> { <div className={'group-container'}> <div className="user-sort" onClick={action(() => (this.groupSort = this.groupSort === 'ascending' ? 'descending' : this.groupSort === 'descending' ? 'none' : 'ascending'))}> <div className="title-group"> - Groups - <div className="group-info" onClick={action(() => GroupManager.Instance?.open())}> - <FontAwesomeIcon icon={'info-circle'} color={'#e8e8e8'} size={'sm'} style={{ backgroundColor: '#1e89d7', borderRadius: '100%', border: '1px solid #1e89d7' }} /> - </div> - - <FontAwesomeIcon icon={this.groupSort === 'ascending' ? 'caret-up' : this.groupSort === 'descending' ? 'caret-down' : 'caret-right'} size="xs" /> + Groups + <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} size={Size.XSMALL} color={StrCast(Doc.UserDoc().userColor)} onClick={action(() => GroupManager.Instance.open())} /> + <IconButton + icon={<FontAwesomeIcon icon={this.groupSort === 'ascending' ? 'caret-up' : this.groupSort === 'descending' ? 'caret-down' : 'caret-right'} />} + size={Size.XSMALL} + color={StrCast(Doc.UserDoc().userColor)} + /> </div> </div> <div className={'groups-list'}>{groupListContents}</div> @@ -657,13 +667,6 @@ export class SharingManager extends React.Component<{}> { } render() { - return <MainViewModal - contents={this.sharingInterface} - isDisplayed={this.isOpen} - interactive={true} - dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} - overlayDisplayedOpacity={this.overlayOpacity} - closeOnExternalClick={this.close} - />; + return <MainViewModal contents={this.sharingInterface} isDisplayed={this.isOpen} interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} closeOnExternalClick={this.close} />; } } diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 1361d99fc..588eff1d1 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -52,13 +52,29 @@ user-select: none; transition: all 0.1s; border-style: none; - // padding: 10px 0px 10px 0px; + position: relative; white-space: nowrap; font-size: 13px; letter-spacing: 2px; text-transform: uppercase; padding-right: 30px; + .contextMenu-item-background { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 0; + filter: opacity(0); + } + + &:hover { + .contextMenu-item-background { + filter: opacity(0.2) !important; + } + } + .contextMenu-item-icon-background { pointer-events: all; background-color: transparent; @@ -133,11 +149,6 @@ // border-top: solid 1px; //TODO:glr clean } -.contextMenu-item:hover { - transition: all 0.1s ease; - background: $light-blue; -} - .contextMenu-description { margin-left: 5px; text-align: left; diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index d54d4dc7b..8412a9aae 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -192,11 +192,11 @@ export class ContextMenu extends React.Component { } return this.filteredItems.map((value, index) => Array.isArray(value) ? ( - <div className="contextMenu-group" + <div + className="contextMenu-group" style={{ - background: StrCast(Doc.UserDoc().userVariantColor) - }} - > + background: StrCast(Doc.UserDoc().userVariantColor), + }}> <div className="contextMenu-description">{value.join(' -> ')}</div> </div> ) : ( @@ -219,16 +219,18 @@ export class ContextMenu extends React.Component { this._height = Number(getComputedStyle(r).height.replace('px', '')); } })} - style={{ - left: this.pageX, ...(this._yRelativeToTop ? { top: this.pageY } : { bottom: this.pageY }), - background: StrCast(Doc.UserDoc().userBackgroundColor) + style={{ + left: this.pageX, + ...(this._yRelativeToTop ? { top: this.pageY } : { bottom: this.pageY }), + background: StrCast(Doc.UserDoc().userBackgroundColor), + color: StrCast(Doc.UserDoc().userColor), }}> {!this.itemsNeedSearch ? null : ( <span className={'search-icon'}> <span className="icon-background"> <FontAwesomeIcon icon="search" size="lg" /> </span> - <input className="contextMenu-item contextMenu-description search" type="text" placeholder="Filter Menu..." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus /> + <input style={{ color: 'black' }} className="contextMenu-item contextMenu-description search" type="text" placeholder="Filter Menu..." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus /> </span> )} {this.menuItems} diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 33f250986..daa2c152a 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -4,6 +4,8 @@ import { observer } from 'mobx-react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { UndoManager } from '../util/UndoManager'; +import { Doc } from '../../fields/Doc'; +import { StrCast } from '../../fields/Types'; export interface OriginalMenuProps { description: string; @@ -90,6 +92,11 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select </span> ) : null} <div className="contextMenu-description">{this.props.description.replace(':', '')}</div> + <div className={`contextMenu-item-background`} + style={{ + background: StrCast(Doc.UserDoc().userColor) + }} + /> </div> ); } else if ('subitems' in this.props) { @@ -103,6 +110,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select style={{ marginLeft: window.innerHeight - this._overPosX - 50 > 0 ? '90%' : '20%', marginTop, + background: StrCast(Doc.UserDoc().userBackgroundColor) }}> {this._items.map(prop => ( <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} /> @@ -133,6 +141,11 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select {this.props.description} <FontAwesomeIcon icon={'angle-right'} size="lg" style={{ position: 'absolute', right: '10px' }} /> </div> + <div className={`contextMenu-item-background`} + style={{ + background: StrCast(Doc.UserDoc().userColor) + }} + /> {submenu} </div> ); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 1a5781df0..ae55c8ebf 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -199,7 +199,7 @@ export class DashboardView extends React.Component { <div className="dashboard-container" key={dashboard[Id]} - style={{ background: this.isUnviewedSharedDashboard(dashboard) && this.selectedDashboardGroup === DashboardGroup.SharedDashboards ? 'green' : shared ? 'blue' : '' }} + style={{ background: this.isUnviewedSharedDashboard(dashboard) && this.selectedDashboardGroup === DashboardGroup.SharedDashboards ? '#6CB982' : shared ? variant : '' }} onContextMenu={e => this.onContextMenu(dashboard, e)} onClick={e => this.clickDashboard(e, dashboard)}> <img diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3522830e5..bab07ac96 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -831,7 +831,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P {shareSymbolIcon + ' ' + shareMode} - {!Doc.noviceMode ? ( + {/* {!Doc.noviceMode ? ( <div className="checkbox"> <div className="checkbox-box"> <input type="checkbox" checked={this.showLayoutAcl} onChange={action(() => (this.showLayoutAcl = !this.showLayoutAcl))} /> @@ -839,7 +839,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P <div className="checkbox-text"> Layout </div> </div> ) : null} - + */} </div> </div> ) : ( diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 347c40c18..7b693c8da 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -261,6 +261,18 @@ export class KeyManager { case 't': PromiseValue(Cast(Doc.UserDoc()['tabs-button-tools'], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); break; + case 'i': + const importBtn = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImports); + if (importBtn) { + MainView.Instance.selectMenu(importBtn); + } + break; + case 's': + const trailsBtn = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyTrails); + if (trailsBtn) { + MainView.Instance.selectMenu(trailsBtn); + } + break; case 'f': if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) { SelectionManager.Views()[0].ComponentView?.search?.('', false, false); @@ -272,14 +284,10 @@ export class KeyManager { } break; case 'e': - Doc.ActiveTool = InkTool.Eraser; + Doc.ActiveTool = (Doc.ActiveTool === InkTool.Eraser ? InkTool.None : InkTool.Eraser); break; case 'p': - Doc.ActiveTool = InkTool.Pen; - break; - case 'o': - const target = SelectionManager.Docs().lastElement(); - target && CollectionDockingView.OpenFullScreen(target); + Doc.ActiveTool = (Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen); break; case 'r': preventDefault = false; diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 0c377730e..b3faff442 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -47,6 +47,10 @@ h1, align-items: center; justify-content: space-between; gap: 10px; + background: rgb(0, 0, 0); + border-radius: 8px; + padding-left: 5px; + padding-right: 5px; } .mainView-snapLines { @@ -190,10 +194,10 @@ h1, left: 0; position: absolute; z-index: 2; - background-color: linen;//$light-gray; + background-color: linen; //$light-gray; .editable-title { - background-color: linen;//$light-gray; + background-color: linen; //$light-gray; } } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index efd8206bf..86e8bab13 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -704,7 +704,6 @@ export class MainView extends React.Component { // prettier-ignore switch (whereFields[0]) { case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location); - case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods); case OpenWhere.add:default:return CollectionDockingView.AddSplit(doc, whereMods, undefined, undefined, keyValue); @@ -750,8 +749,7 @@ export class MainView extends React.Component { @computed get leftMenuPanel() { return ( - <div key="menu" className="mainView-leftMenuPanel" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), - display: LightboxView.LightboxDoc ? 'none' : undefined }}> + <div key="menu" className="mainView-leftMenuPanel" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), display: LightboxView.LightboxDoc ? 'none' : undefined }}> <DocumentView Document={Doc.MyLeftSidebarMenu} DataDoc={undefined} @@ -806,14 +804,17 @@ export class MainView extends React.Component { {this._hideUI ? null : this.leftMenuPanel} <div key="inner" className={`mainView-innerContent${this.colorScheme}`}> {this.flyout} - <div className="mainView-libraryHandle" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }} onPointerDown={this.onFlyoutPointerDown}> + <div + className="mainView-libraryHandle" + style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), left: leftMenuFlyoutWidth - 10 /* ~half width of handle */, display: !this._leftMenuFlyoutWidth ? 'none' : undefined }} + onPointerDown={this.onFlyoutPointerDown}> <FontAwesomeIcon icon="chevron-left" color={StrCast(Doc.UserDoc().userColor)} style={{ opacity: '50%' }} size="sm" /> </div> <div className="mainView-innerContainer" style={{ width: `calc(100% - ${width}px)` }}> {this.dockingContent} {this._hideUI ? null : ( - <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ right: this.propertiesWidth() - 1, background : 'linen' }}> + <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ right: this.propertiesWidth() - 1, background: 'linen' }}> <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={this.colorScheme === ColorScheme.Dark ? Colors.WHITE : Colors.BLACK} size="sm" /> </div> )} @@ -880,7 +881,7 @@ export class MainView extends React.Component { @computed get docButtons() { return !Doc.MyDockedBtns ? null : ( - <div className="mainView-docButtons" ref={this._docBtnRef}> + <div className="mainView-docButtons" style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor) }} ref={this._docBtnRef}> <CollectionLinearView Document={Doc.MyDockedBtns} DataDoc={undefined} diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 6105cc1b5..2e3668268 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -56,24 +56,25 @@ export class PropertiesButtons extends React.Component<{}, {}> { propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => { const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc; const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true); - return !targetDoc ? null : <Toggle - toggleStatus={BoolCast(targetDoc[property])} - text={label(targetDoc?.[property])} - color={StrCast(Doc.UserDoc().userColor)} - icon={icon(targetDoc?.[property] as any)} - iconPlacement={'left'} - align={'flex-start'} - fillWidth={true} - toggleType={ToggleType.BUTTON} - onClick={undoable(() => { - if (SelectionManager.Views().length > 1) { - SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property)); - } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property); - }, property)} - /> + return !targetDoc ? null : ( + <Toggle + toggleStatus={BoolCast(targetDoc[property])} + text={label(targetDoc?.[property])} + color={StrCast(Doc.UserDoc().userColor)} + icon={icon(targetDoc?.[property] as any)} + iconPlacement={'left'} + align={'flex-start'} + fillWidth={true} + toggleType={ToggleType.BUTTON} + onClick={undoable(() => { + if (SelectionManager.Views().length > 1) { + SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property)); + } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property); + }, property)} + /> + ); }; - // this implments a container pattern by marking the targetDoc (collection) as a lightbox // that always fits its contents to its container and that hides all other documents when // a link is followed that targets a 'lightbox' destination @@ -110,7 +111,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { (dv, doc) => { const tdoc = dv?.rootDoc || doc; const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : ''; - tdoc._layout_showTitle = newtitle; + tdoc._layout_showTitle = newtitle ? newtitle : undefined; } ); } @@ -148,7 +149,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get clustersButton() { return this.propertyToggleBtn( - on => (on ?'DISABLE CLUSTERS' : 'HIGHLIGHT CLUSTERS'), + on => (on ? 'DISABLE CLUSTERS' : 'HIGHLIGHT CLUSTERS'), '_freeform_useClusters', on => `${on ? 'Hide' : 'Show'} clusters`, on => <FaBraille /> @@ -163,12 +164,13 @@ export class PropertiesButtons extends React.Component<{}, {}> { ); } - @computed get forceActiveButton() { //select text + @computed get forceActiveButton() { + //select text return this.propertyToggleBtn( - on => on ? 'INACTIVE INTERACTION' : 'ACTIVE INTERACTION', + on => (on ? 'INACTIVE INTERACTION' : 'ACTIVE INTERACTION'), '_forceActive', on => `${on ? 'Select to activate' : 'Contents always active'} `, - on => <MdTouchApp/> // 'eye' + on => <MdTouchApp /> // 'eye' ); } @@ -218,7 +220,8 @@ export class PropertiesButtons extends React.Component<{}, {}> { } @computed get captionButton() { - return this.propertyToggleBtn( //DEVELOPER + return this.propertyToggleBtn( + //DEVELOPER on => (on ? 'HIDE CAPTION' : 'SHOW CAPTION'), //'Caption', '_layout_showCaption', on => `${on ? 'Hide' : 'Show'} caption footer`, @@ -227,17 +230,19 @@ export class PropertiesButtons extends React.Component<{}, {}> { ); } - @computed get chromeButton() { // developer -- removing UI decoration + @computed get chromeButton() { + // developer -- removing UI decoration return this.propertyToggleBtn( - on => on ? 'ENABLE UI CONTROLS' : 'DISABLE UI CONTROLS', + on => (on ? 'ENABLE UI CONTROLS' : 'DISABLE UI CONTROLS'), '_chromeHidden', on => `${on ? 'Show' : 'Hide'} editing UI`, - on => on? <TbEditCircle/> : <TbEditCircleOff/> , // 'edit', + on => (on ? <TbEditCircle /> : <TbEditCircleOff />), // 'edit', (dv, doc) => ((dv?.rootDoc || doc)._chromeHidden = !(dv?.rootDoc || doc)._chromeHidden) ); } - @computed get layout_autoHeightButton() { // store previous dimensions to store old values + @computed get layout_autoHeightButton() { + // store previous dimensions to store old values return this.propertyToggleBtn( on => 'Auto\xA0Size', '_layout_autoHeight', @@ -251,7 +256,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { on => (on ? 'HIDE GRID' : 'DISPLAY GRID'), '_freeform_backgroundGrid', on => `Display background grid in collection`, - on => (on ? <MdGridOff /> :<MdGridOn /> ) //'border-all' + on => (on ? <MdGridOff /> : <MdGridOn />) //'border-all' ); } @@ -288,13 +293,14 @@ export class PropertiesButtons extends React.Component<{}, {}> { // } // ); // } - @computed get snapButton() { // THESE ARE NOT COMING + @computed get snapButton() { + // THESE ARE NOT COMING return this.propertyToggleBtn( on => (on ? 'HIDE SNAP LINES' : 'SHOW SNAP LINES'), 'freeform_snapLines', on => `Display snapping lines when objects are dragged`, on => <TfiBarChart />, //'th', - undefined, + undefined ); } @@ -346,11 +352,11 @@ export class PropertiesButtons extends React.Component<{}, {}> { const followLoc = this.selectedDoc._followLinkLocation; const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); - if (followLoc === OpenWhere.lightbox && !linkedToLightboxView()) return 'linkInPlace' - else if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight' - else if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal' - else if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail' - else return 'nothing' + if (followLoc === OpenWhere.lightbox && !linkedToLightboxView()) return 'linkInPlace'; + else if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight'; + else if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal'; + else if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail'; + else return 'nothing'; } @computed @@ -362,22 +368,20 @@ export class PropertiesButtons extends React.Component<{}, {}> { ['linkInPlace', 'Open Link in Lightbox'], ['linkOnRight', 'Open Link on Right'], ]; - + const items: IListItemProps[] = buttonList.map(value => { - return ( - { - text: value[1], - val: value[1], - } - ); + return { + text: value[1], + val: value[1], + }; }); - console.log("click val: ", this.onClickVal) + console.log('click val: ', this.onClickVal); return !this.selectedDoc ? null : ( <Dropdown - tooltip={'Choose onClick behavior'} + tooltip={'Choose onClick behavior'} items={items} selectedVal={this.onClickVal} - setSelectedVal={(val) => this.handleOptionChange(val as string)} + setSelectedVal={val => this.handleOptionChange(val as string)} title={'Choose onClick behaviour'} color={StrCast(Doc.UserDoc().userColor)} dropdownType={DropdownType.SELECT} diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 6a54f0002..395aa2b61 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -3,11 +3,10 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; -import { Cast, NumCast, StrCast } from '../../fields/Types'; -import { CollectionViewType } from '../documents/DocumentTypes'; +import { Cast, StrCast } from '../../fields/Types'; import { DocFocusOrOpen } from '../util/DocumentManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; -import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; import './PropertiesDocContextSelector.scss'; type PropertiesDocContextSelectorProps = { @@ -19,7 +18,6 @@ type PropertiesDocContextSelectorProps = { @observer export class PropertiesDocContextSelector extends React.Component<PropertiesDocContextSelectorProps> { - @computed get _docs() { if (!this.props.DocView) return []; const target = this.props.DocView.props.Document; @@ -40,7 +38,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC }, new Set<Doc>()) .keys() ); - console.log("embeddings " + embeddings.length); + console.log('embeddings ' + embeddings.length); return doclayouts .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document)) @@ -56,7 +54,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC }; render() { - if (this._docs.length < 1) return undefined + if (this._docs.length < 1) return undefined; return ( <div> {this.props.hideTitle ? null : <p key="contexts">Contexts:</p>} diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index 060b506e3..b79486167 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -42,16 +42,6 @@ padding: 0; margin-top: -5; } - - .propertiesView-acls-checkbox { - margin-top: -15px; - margin-bottom: -10px; - - .propertiesView-acls-checkbox-text { - display: inline; - font-size: 9px; - } - } } .change-buttons { @@ -68,14 +58,19 @@ } } + .propertiesView-acls-checkbox { + float: right; + margin-left: 50px; + } + .propertiesView-shareDropDown{ margin-right: 10px; min-width: 65px; & .propertiesView-shareDropDownNone{ - height: 16px; padding: 0px; padding-left: 3px; + padding-right: 3px; background: grey; color: rgb(71, 71, 71); border-radius: 6px; @@ -83,18 +78,18 @@ } & .propertiesView-shareDropDownEdit, .propertiesView-shareDropDownAdmin{ - height: 16px; padding: 0px; padding-left: 3px; + padding-right: 3px; background: rgb(254, 254, 199); color: rgb(75, 75, 5); border-radius: 6px; border: 1px solid rgb(75, 75, 5); } & .propertiesView-shareDropDownAugment{ - height: 16px; padding: 0px; padding-left: 3px; + padding-right: 3px; background: rgb(208, 255, 208); color:rgb(19, 80, 19); border-radius: 6px; @@ -102,18 +97,18 @@ } & .propertiesView-shareDropDownView{ - height: 16px; padding: 0px; padding-left: 3px; + padding-right: 3px; background: rgb(213, 213, 255); color: rgb(25, 25, 101); border-radius: 6px; border: 1px solid rgb(25, 25, 101); } & .propertiesView-shareDropDownNot-Shared{ - height: 16px; padding: 0px; padding-left: 3px; + padding-right: 3px; background: rgb(255, 207, 207); color: rgb(138, 47, 47); border-radius: 6px; @@ -177,19 +172,7 @@ } .expansion-button { - margin-left: -15px; - margin-right: 20px; - - .expansion-button-icon { - width: 11px; - height: 11px; - color: black; - - &:hover { - color: rgb(131, 131, 131); - cursor: pointer; - } - } + margin-right: 10px; } .propertiesView-sharingTable { @@ -238,6 +221,11 @@ } } + .propertiesView-permissions-select { + background: inherit; + border: none; + } + .propertiesView-field { display: flex; font-size: 7px; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index cb0663554..27b9c3c7a 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -3,7 +3,7 @@ import { IconLookup } from '@fortawesome/fontawesome-svg-core'; import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@material-ui/core'; -import { Button, Colors, EditableText, NumberInput, Size, Slider, Type } from 'browndash-components'; +import { Button, Colors, EditableText, IconButton, NumberInput, Size, Slider, Type } from 'browndash-components'; import { concat } from 'lodash'; import { Lambda, action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -367,17 +367,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { */ @computed get expansionIcon() { return ( - <Tooltip title={<div className="dash-tooltip">Show more permissions</div>}> - <div - className="expansion-button" - onPointerDown={() => { + <div className="expansion-button" > + <IconButton + icon={<FontAwesomeIcon icon={'ellipsis-h'} />} + size={Size.XSMALL} + color={StrCast(Doc.UserDoc().userColor)} + onClick={action(() => { if (this.selectedDocumentView || this.selectedDoc) { SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined, this.selectedDoc); } - }}> - <FontAwesomeIcon className="expansion-button-icon" icon="ellipsis-h" color="black" size="sm" /> - </div> - </Tooltip> + })} + /> + </div> ); } @@ -417,7 +418,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { <div> <div className={'propertiesView-shareDropDown'}> <div className={`propertiesView-shareDropDown${permission}`}> - <div className="propertiesView-shareDropDown">{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div> + <div >{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div> </div> </div> </div> @@ -449,6 +450,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { const target = docs[0]; const showAdmin = GetEffectiveAcl(target) == AclAdmin; + console.log(GetEffectiveAcl(target), Doc.GetProto(target)[`acl-${normalizeEmail(Doc.CurrentUserEmail)}`]) const individualTableEntries = []; const usersAdded: string[] = []; // all shared users being added - organized by denormalized email @@ -512,28 +514,29 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { } }); - // public permission - const publicPermission = StrCast((this.layoutDocAcls ? target : Doc.GetProto(target))['acl-Guest']); + // guest permission + const guestPermission = StrCast((this.layoutDocAcls ? target : Doc.GetProto(target))['acl-Guest']); return ( <div> - <br /> - <div className="propertiesView-sharingTable">{<div> {individualTableEntries}</div>}</div> + <div> + <br></br> Individuals with Access to this Document + </div> + <div className="propertiesView-sharingTable" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}> + {<div> {individualTableEntries}</div>} + </div> {groupTableEntries.length > 0 ? ( <div> <div> - {' '} - <br></br> Groups with Access to this Document{' '} + <br></br> Groups with Access to this Document + </div> + <div className="propertiesView-sharingTable" style={{background: StrCast(Doc.UserDoc().userBackgroundColor), color: StrCast(Doc.UserDoc().userColor)}}> + {<div> {groupTableEntries}</div>} </div> - <div className="propertiesView-sharingTable">{<div> {groupTableEntries}</div>}</div> </div> ) : null} - Guest - <div>{this.colorACLDropDown('Guest', true, publicPermission!, true)}</div> - <div> - {' '} - <br></br> Individual Users with Access to this Document{' '} - </div> + <br></br> Guest + <div>{this.colorACLDropDown('Guest', showAdmin, guestPermission!, true)}</div> </div> ); } @@ -1145,26 +1148,17 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { return <PropertiesSection title="Sharing & Permissions" content={<> - <div className="propertiesView-buttonContainer"> - {!Doc.noviceMode ? ( - <div className="propertiesView-buttonContainer"> - <div className="propertiesView-acls-checkbox"> - <div className="propertiesView-acls-checkbox-text"> Show / Contol Layout Permissions </div> - <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> - </div> - {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}> - <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}> - <FontAwesomeIcon icon="redo-alt" color="white" size="1x" /> - </button> - </Tooltip> */} - </div> - ) : null} + {/* <div className="propertiesView-buttonContainer"> */} + <div className="propertiesView-acls-checkbox"> + Layout Permissions + <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> + </div> {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}> <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}> <FontAwesomeIcon icon="redo-alt" size="1x" /> </button> </Tooltip> */} - </div> + {/* </div> */} {this.sharingTable} </>} isOpen={this.openSharing} @@ -1534,7 +1528,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { <option value={OpenWhere.addRight}>Opening in new right pane</option> <option value={OpenWhere.replaceLeft}>Replacing left tab</option> <option value={OpenWhere.replaceRight}>Replacing right tab</option> - <option value={OpenWhere.fullScreen}>Overlaying current tab</option> <option value={OpenWhere.lightbox}>Opening in lightbox</option> <option value={OpenWhere.add}>Opening in new tab</option> <option value={OpenWhere.replace}>Replacing current tab</option> diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index 80c878386..c06bb287e 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -31,8 +31,8 @@ .styleProvider-treeView-icon, .styleProvider-treeView-icon-active { - margin-left: 0.25rem; - margin-right: 0.25rem; + margin-left: 0; + margin-right: 0; } .styleProvider-treeView-icon { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a030c7052..bbbad3690 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -1,7 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { Shadows } from 'browndash-components'; +import { IconButton, Shadows, Size } from 'browndash-components'; import { action, runInAction } from 'mobx'; import { extname } from 'path'; import { Doc, Opt, StrListCast } from '../../fields/Doc'; @@ -22,6 +22,7 @@ import { DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { SliderBox } from './nodes/SliderBox'; +import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs' import './StyleProvider.scss'; import React = require('react'); @@ -109,11 +110,11 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps } return Doc.toIcon(doc, isEmpty ? undefined : isOpen); case StyleProp.TreeViewSortings: - const allSorts: { [key: string]: { color: string; label: string } | undefined } = {}; - allSorts[TreeSort.Down] = { color: 'blue', label: '↓' }; - allSorts[TreeSort.Up] = { color: 'crimson', label: '↑' }; - if (doc?._type_collection === CollectionViewType.Freeform) allSorts[TreeSort.Zindex] = { color: 'green', label: 'z' }; - allSorts[TreeSort.None] = { color: 'darkgray', label: '\u00A0\u00A0\u00A0' }; + const allSorts: { [key: string]: { color: string; icon: JSX.Element | string } | undefined } = {}; + allSorts[TreeSort.Down] = { color: Colors.MEDIUM_BLUE, icon: <BsArrowDown/> }; + allSorts[TreeSort.Up] = { color: 'crimson', icon: <BsArrowUp/> }; + if (doc?._type_collection === CollectionViewType.Freeform) allSorts[TreeSort.Zindex] = { color: 'green', icon: 'Z' }; + allSorts[TreeSort.None] = { color: 'darkgray', icon: <BsArrowDownUp/> }; return allSorts; case StyleProp.Highlighting: if (doc && (Doc.IsSystem(doc) || doc.type === DocumentType.FONTICON)) return undefined; @@ -323,18 +324,19 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps } export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, offIcon: IconProp, clickFunc?: () => void) { + const color = StrCast(Doc.UserDoc().userColor); return ( - <div - title={field} - className={`styleProvider-treeView-icon${doc[field] ? '-active' : ''}`} + <IconButton + size={Size.XSMALL} + color={color} + icon={<FontAwesomeIcon icon={(doc[field] ? (onIcon as any) : offIcon) as IconProp} />} onClick={undoBatch( action((e: React.MouseEvent) => { e.stopPropagation(); clickFunc ? clickFunc() : (doc[field] = doc[field] ? undefined : true); }) - )}> - <FontAwesomeIcon icon={(doc[field] ? (onIcon as any) : offIcon) as IconProp} size="sm" /> - </div> + )} + /> ); } /** @@ -342,7 +344,7 @@ export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, */ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string) { if (doc && property.split(':')[0] === StyleProp.Decorations) { - return doc._type_collection === CollectionViewType.Docking + return doc._type_collection === CollectionViewType.Docking || Doc.IsSystem(doc) ? null : DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => DocFocusOrOpen(doc, { toggleTarget: true, willZoomCentered: true, zoomScale: 0 }, DocCast(doc?.embedContainer ?? doc?.annotationOn))); } diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx index aaca7110e..caf04cc1b 100644 --- a/src/client/views/UndoStack.tsx +++ b/src/client/views/UndoStack.tsx @@ -5,7 +5,8 @@ import { UndoManager } from '../util/UndoManager'; import './UndoStack.scss'; import { StrCast } from '../../fields/Types'; import { Doc } from '../../fields/Doc'; -import { Popup, Type } from 'browndash-components'; +import { Popup, Type, isDark } from 'browndash-components'; +import { Colors } from './global/globalEnums'; interface UndoStackProps { width?: number; @@ -17,18 +18,19 @@ export class UndoStack extends React.Component<UndoStackProps> { @observable static HideInline: boolean; @observable static Expand: boolean; render() { + const background = UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userBackgroundColor) return this.props.inline && UndoStack.HideInline ? null : ( <div className="undoStack-outerContainer"> <Popup text={'Undo/Redo Stack'} - color={StrCast(Doc.UserDoc().userVariantColor)} + color={UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userVariantColor)} placement={`top-start`} type={Type.TERT} popup={ <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} style={{ - background: UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userBackgroundColor), - color: StrCast(Doc.UserDoc().userColor) + background: background, + color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY }}> {UndoManager.undoStackNames.map((name, i) => ( <div className="undoStack-resultContainer" key={i}> diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 4c15d5eed..a4c5229aa 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -95,6 +95,13 @@ position: relative; } +.lm_maximised .lm_header { + background-color: #000000; +} +.lm_maximised .lm_tab { + width: 100%; +} + .lm_stack { position: relative; } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 8d1b46ebb..16982595d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -127,28 +127,6 @@ export class CollectionDockingView extends CollectionSubView() { } @undoBatch - public static OpenFullScreen(doc: Doc) { - SelectionManager.DeselectAll(); - const instance = CollectionDockingView.Instance; - if (instance) { - if (doc._type_collection === CollectionViewType.Docking && doc.layout_fieldKey === 'layout') { - return DashboardView.openDashboard(doc); - } - const newItemStackConfig = { - type: 'stack', - content: [CollectionDockingView.makeDocumentConfig(Doc.MakeEmbedding(doc))], - }; - const docconfig = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); - instance._goldenLayout.root.contentItems[0].addChild(docconfig); - docconfig.callDownwards('_$init'); - instance._goldenLayout._$maximiseItem(docconfig); - instance._goldenLayout.emit('stateChanged'); - instance.stateChanged(); - } - return true; - } - - @undoBatch @action public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean, keyValue?: boolean): boolean { const instance = CollectionDockingView.Instance; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 9eb716763..5135cfb57 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -33,7 +33,7 @@ import { LightboxView } from '../LightboxView'; import { MainView } from '../MainView'; import { DefaultStyleProvider } from '../StyleProvider'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocumentView, OpenWhereMod } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhereMod } from '../nodes/DocumentView'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { CollectionDockingView } from './CollectionDockingView'; import './CollectionMenu.scss'; @@ -129,7 +129,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { docViewPath={returnEmptyDoclist} moveDocument={returnFalse} addDocument={returnFalse} - addDocTab={returnFalse} + addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} removeDocument={returnFalse} ScreenToLocalTransform={this.buttonBarXf} @@ -154,21 +154,21 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { const hardCodedButtons = ( <div className={`hardCodedButtons`}> - <Toggle - toggleType={ToggleType.BUTTON} - type={Type.PRIM} - color={StrCast(Doc.UserDoc().userColor)} - onClick={this.toggleTopBar} - toggleStatus={SettingsManager.headerBarHeight > 0} + <Toggle + toggleType={ToggleType.BUTTON} + type={Type.PRIM} + color={StrCast(Doc.UserDoc().userColor)} + onClick={this.toggleTopBar} + toggleStatus={SettingsManager.headerBarHeight > 0} icon={<FontAwesomeIcon icon={headerIcon} size="lg" />} tooltip={headerTitle} /> - <Toggle - toggleType={ToggleType.BUTTON} + <Toggle + toggleType={ToggleType.BUTTON} type={Type.PRIM} - color={StrCast(Doc.UserDoc().userColor)} - onClick={this.toggleProperties} - toggleStatus={SettingsManager.propertiesWidth > 0} + color={StrCast(Doc.UserDoc().userColor)} + onClick={this.toggleProperties} + toggleStatus={SettingsManager.propertiesWidth > 0} icon={<FontAwesomeIcon icon={propIcon} size="lg" />} tooltip={propTitle} /> @@ -178,11 +178,12 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> { // NEW BUTTONS //dash col linear view buttons const contMenuButtons = ( - <div className="collectionMenu-container" - style={{ - background: StrCast(Doc.UserDoc().userBackgroundColor), - // borderColor: StrCast(Doc.UserDoc().userColor) - }} > + <div + className="collectionMenu-container" + style={{ + background: StrCast(Doc.UserDoc().userBackgroundColor), + // borderColor: StrCast(Doc.UserDoc().userColor) + }}> {this.contMenuButtons} {hardCodedButtons} </div> diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index b9f13b188..67b7b39dd 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -377,7 +377,6 @@ export class TabDocView extends React.Component<TabDocViewProps> { } } return LightboxView.AddDocTab(doc, location); - case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack, undefined, keyValue); case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack, undefined, keyValue); diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 85f99b9c2..d22e85880 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -13,7 +13,7 @@ .treeView-container-active { .bullet-outline { position: relative; - width: $TREE_BULLET_WIDTH; + width: fit-content; color: $medium-gray; transform: scale(0.5); display: inline-flex; @@ -21,7 +21,6 @@ } .treeView-bulletIcons { - // width: $TREE_BULLET_WIDTH; width: 100%; height: 100%; position: relative; @@ -43,11 +42,12 @@ justify-content: center; align-items: center; position: relative; - width: $TREE_BULLET_WIDTH; + width: fit-content; min-height: 20px; color: $medium-gray; border: #80808030 1px solid; border-radius: 5px; + z-index: 1; } } @@ -55,9 +55,6 @@ position: absolute; height: max-content; pointer-events: none; - color: white; - border-radius: 4px; - font-size: 10px; } .treeView-container-active { @@ -105,10 +102,26 @@ align-items: center; width: max-content; border-radius: 5px; + overflow: hidden; + position: relative; + z-index: 1; + + .treeView-background { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 0; + filter: opacity(0); + } &:hover { - background-color: #bdddf5; + .treeView-background { + filter: opacity(0.2) !important; + } } + //align-items: center; ::-webkit-scrollbar { @@ -141,6 +154,7 @@ opacity: 0.75; pointer-events: all; cursor: pointer; + z-index: 1; > svg { margin-left: 0.25rem; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index fa9f895fd..51c70633c 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -222,10 +222,8 @@ export class TreeView extends React.Component<TreeViewProps> { this.treeViewOpen = !this.treeViewOpen; } else { // choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns, (2) has no context field ... otherwise make a new embedding - const bestEmbedding = docView.rootDoc.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.props.Document) - ? docView.rootDoc - : Doc.BestEmbedding(docView.rootDoc); - this.props.addDocTab(bestEmbedding, OpenWhere.lightbox); + const bestEmbedding = docView.rootDoc.author === Doc.CurrentUserEmail && !Doc.IsDataProto(docView.props.Document) ? docView.rootDoc : Doc.BestEmbedding(docView.rootDoc); + this.props.addDocTab(bestEmbedding, OpenWhere.lightbox); } }; @@ -539,9 +537,9 @@ export class TreeView extends React.Component<TreeViewProps> { @computed get renderContent() { TraceMobx(); const expandKey = this.treeViewExpandedView; - const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } }) ?? {}; - const color = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Color) - console.log("tree view", color, this.doc.title, Doc.IsSystem(this.doc)) + const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; icon: JSX.Element | string } }) ?? {}; + const color = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Color); + console.log('tree view', color, this.doc.title, Doc.IsSystem(this.doc)); if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) { const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); const sortKeys = Object.keys(sortings); @@ -581,12 +579,28 @@ export class TreeView extends React.Component<TreeViewProps> { ); } return ( - <div style={{ - color: color - }}> + <div + style={{ + color: color, + }}> {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : ( - <div className={'treeView-sorting'} style={{ background: sortings[sorting]?.color }}> - {sortings[sorting]?.label} + <div className={'treeView-sorting'}> + <IconButton + color={sortings[sorting]?.color} + size={Size.XSMALL} + icon={sortings[sorting]?.icon} + onPointerDown={e => { + downX = e.clientX; + downY = e.clientY; + e.stopPropagation(); + }} + onClick={undoable(e => { + if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { + !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + e.stopPropagation(); + } + }, 'sort order')} + /> </div> )} <ul @@ -689,7 +703,7 @@ export class TreeView extends React.Component<TreeViewProps> { @computed get renderBullet() { TraceMobx(); const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question'; - const color = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Color) + const color = StrCast(Doc.UserDoc().userColor); const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined; return ( <div @@ -710,26 +724,19 @@ export class TreeView extends React.Component<TreeViewProps> { }> {this.props.treeView.outlineMode ? ( !(this.doc.text as RichTextField)?.Text ? null : ( - <IconButton - color={color} - icon={<FontAwesomeIcon icon={[this.childDocs?.length && !this.treeViewOpen ? 'fas' : 'far', 'circle']} />} - size={Size.XSMALL} - /> + <IconButton color={color} icon={<FontAwesomeIcon icon={[this.childDocs?.length && !this.treeViewOpen ? 'fas' : 'far', 'circle']} />} size={Size.XSMALL} /> ) ) : ( <div className="treeView-bulletIcons" style={{ color: Doc.IsSystem(DocCast(this.doc.proto)) ? 'red' : undefined }}> - <IconButton - color={color} - icon={<FontAwesomeIcon size="sm" icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'} />} - size={Size.XSMALL} - /> - {this.onCheckedClick ? null : - <IconButton - color={color} - icon={<FontAwesomeIcon icon={iconType as IconProp} />} - size={Size.XSMALL} - /> - } + {this.onCheckedClick ? ( + <IconButton + color={color} + icon={<FontAwesomeIcon size="sm" icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'} />} + size={Size.XSMALL} + /> + ) : ( + <IconButton color={color} icon={<FontAwesomeIcon icon={iconType as IconProp} />} size={Size.XSMALL} /> + )} </div> )} </div> @@ -757,21 +764,19 @@ export class TreeView extends React.Component<TreeViewProps> { @observable headerEleWidth = 0; @computed get titleButtons() { const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations); + const color = StrCast(Doc.UserDoc().userColor); return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : ( <> {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */} - {this.doc._layout_hideContextMenu ? null : ( - <FontAwesomeIcon - title="context menu" - key="bars" - icon="bars" - size="sm" - onClick={e => { - this.showContextMenu(e); - e.stopPropagation(); - }} - /> - )} + <IconButton + color={color} + icon={<FontAwesomeIcon icon="bars" />} + size={Size.XSMALL} + onClick={e => { + this.showContextMenu(e); + e.stopPropagation(); + }} + /> {Doc.noviceMode ? null : this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( <span className="collectionTreeView-keyHeader" title="type of expanded data" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}> {this.treeViewExpandedView} @@ -1000,6 +1005,12 @@ export class TreeView extends React.Component<TreeViewProps> { onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> {contents} + <div + className={`treeView-background`} + style={{ + background: StrCast(Doc.UserDoc().userColor), + }} + /> </div> {this.renderBorder} </> diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 079b94428..7e574e839 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -161,7 +161,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque }); }) ); - } else if (e.key === 's' && e.ctrlKey) { + } /* else if (e.key === 's' && e.ctrlKey) { e.preventDefault(); const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!; slide.x = x; @@ -178,7 +178,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque this.pasteTable(ns, x, y); })(); e.stopPropagation(); - } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) { + }*/ else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) { FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : ''; FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note'); this.props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this.props.xPadding === 0)); diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index c5e98da86..3acbd1a32 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -305,8 +305,8 @@ export class NewLightboxView extends React.Component<LightboxViewProps> { renderDepth={0} rootSelected={returnTrue} docViewPath={returnEmptyDoclist} - docFilters={this.docFilters} - docRangeFilters={returnEmptyFilter} + childFilters={this.docFilters} + childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} addDocument={undefined} removeDocument={undefined} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4211b8a81..f9fa1955f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -70,7 +70,6 @@ export enum OpenWhere { addRight = 'add:right', addBottom = 'add:bottom', close = 'close', - fullScreen = 'fullScreen', toggle = 'toggle', toggleRight = 'toggle:right', replace = 'replace', @@ -800,7 +799,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps !more && moreItems.length && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'compass' }); } const constantItems: ContextMenuProps[] = []; - constantItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'layer-group' }); if (!Doc.IsSystem(this.rootDoc)) { constantItems.push({ description: 'Export as Zip file', icon: 'download', event: async () => Doc.Zip(this.props.Document) }); (this.rootDoc._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); @@ -809,7 +807,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); } } - cm.addItem({ description: 'General...', noexpand: !Doc.IsSystem(this.rootDoc), subitems: constantItems, icon: 'question' }); + constantItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'layer-group' }); + cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); const help = cm.findByDescription('Help...'); const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index 3ec53beac..da1b89200 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -86,10 +86,10 @@ export class FontIconBox extends DocComponent<ButtonProps>() { } Icon = (color: string, iconFalse?: boolean) => { let icon; - if (iconFalse ) { + if (iconFalse) { icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any; - if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} /> - else return null + if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />; + else return null; } icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any; const trailsIcon = () => <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />; @@ -124,36 +124,38 @@ export class FontIconBox extends DocComponent<ButtonProps>() { */ @computed get numberDropdown() { let type: NumberDropdownType; - switch(this.type) { - case ButtonType.NumberDropdownButton: - type = 'dropdown' + switch (this.type) { + case ButtonType.NumberDropdownButton: + type = 'dropdown'; break; case ButtonType.NumberInlineButton: - type = 'input' + type = 'input'; break; case ButtonType.NumberSliderButton: default: - type = 'slider' + type = 'slider'; break; } - const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined }); + const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: value === undefined }); const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); // Script for checking the outcome of the toggle const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3))); const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>; - return <NumberDropdown - color={color} - numberDropdownType={type} - showPlusMinus={false} - tooltip={this.label} - type={Type.PRIM} - min={NumCast(this.rootDoc.numBtnMin, 0)} - max={NumCast(this.rootDoc.numBtnMax, 100)} - number={checkResult} - setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)} - fillWidth - /> + return ( + <NumberDropdown + color={color} + numberDropdownType={type} + showPlusMinus={false} + tooltip={this.label} + type={Type.PRIM} + min={NumCast(this.rootDoc.numBtnMin, 0)} + max={NumCast(this.rootDoc.numBtnMax, 100)} + number={checkResult} + setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)} + fillWidth + /> + ); } /** @@ -202,84 +204,69 @@ export class FontIconBox extends DocComponent<ButtonProps>() { let dropdown = true; let getStyle: (val: string) => any = () => {}; let icon: IconProp = 'caret-down'; - let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView') + let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView'); try { if (isViewDropdown) { const selectedDocs: Doc[] = SelectionManager.Docs(); const selected = SelectionManager.Docs().lastElement(); - console.log('selected') + console.log('selected'); if (selected) { if (StrCast(selected.type) === DocumentType.COL) { text = StrCast(selected._type_collection); - console.log("collection selected", text) + console.log('collection selected', text); } else { - console.log("doc selected", selected.title); + console.log('doc selected', selected.title); dropdown = false; if (selectedDocs.length > 1) { - text = selectedDocs.length + " selected" + text = selectedDocs.length + ' selected'; } else { text = Utils.cleanDocumentType(StrCast(selected.type) as DocumentType); icon = Doc.toIcon(selected); } - return <Popup - icon={<FontAwesomeIcon size={'1x'} icon={icon} />} - text={text} - type={Type.TERT} - color={color} - popup={<SelectedDocView selectedDocs={selectedDocs}/>} - fillWidth - /> + return <Popup icon={<FontAwesomeIcon size={'1x'} icon={icon} />} text={text} type={Type.TERT} color={color} popup={<SelectedDocView selectedDocs={selectedDocs} />} fillWidth />; } } else { dropdown = false; - return <Button - text={`None Selected`} - type={Type.TERT} - color={color} - fillWidth - inactive - /> + return <Button text={`None Selected`} type={Type.TERT} color={color} fillWidth inactive />; } noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; - } else { + } else { text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); - getStyle = (val: string) => { return { fontFamily: val } } + getStyle = (val: string) => { + return { fontFamily: val }; + }; } } catch (e) { console.log(e); } - console.log("current item: ", text); + console.log('current item: ', text); // Get items to place into the list const list: IListItemProps[] = this.buttonList .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value)) - .map(value => ( - { - text: value.charAt(0).toUpperCase() + value.slice(1), - val: value, - style: getStyle(value), - onClick: undoable(() => script.script.run({ self: this.rootDoc, value }), value) - // shortcut: '#', - } - )); - + .map(value => ({ + text: value.charAt(0).toUpperCase() + value.slice(1), + val: value, + style: getStyle(value), + onClick: undoable(() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), value), + // shortcut: '#', + })); return ( - <Dropdown + <Dropdown selectedVal={text} - setSelectedVal={undoable((val) => script.script.run({ self: this.rootDoc, val }), `dropdown select ${this.label}`)} - color={color} - type={isViewDropdown ? Type.TERT : Type.PRIM} - dropdownType={DropdownType.SELECT} + setSelectedVal={undoable(val => script.script.run({ this: this.layoutDoc, self: this.rootDoc, val }), `dropdown select ${this.label}`)} + color={color} + type={isViewDropdown ? Type.TERT : Type.PRIM} + dropdownType={DropdownType.SELECT} items={list} tooltip={this.label} fillWidth /> - ) + ); } - @computed get colorScript() { return ScriptCast(this.rootDoc.script); } @@ -290,14 +277,14 @@ export class FontIconBox extends DocComponent<ButtonProps>() { @computed get colorButton() { const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - const curColor = this.colorScript?.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent'; + const curColor = this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent'; const tooltip: string = StrCast(this.rootDoc.toolTip); return ( - <ColorPicker - setSelectedColor={(value) => { + <ColorPicker + setSelectedColor={value => { const s = this.colorScript; - s && undoable(() => s.script.run({ self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)(); + s && undoable(() => s.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)(); }} selectedColor={curColor} type={Type.PRIM} @@ -306,7 +293,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { tooltip={tooltip} label={this.label} /> - ) + ); } @computed get toggleButton() { @@ -315,25 +302,24 @@ export class FontIconBox extends DocComponent<ButtonProps>() { const tooltip: string = StrCast(this.rootDoc.toolTip); const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; // Colors const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - console.log(tooltip, toggleStatus); return ( - <Toggle - tooltip={`Toggle ${tooltip}`} - toggleType={ToggleType.BUTTON} - type={Type.PRIM} - toggleStatus={toggleStatus} - text={buttonText} - color={color} - icon={this.Icon(color)!} + <Toggle + tooltip={`Toggle ${tooltip}`} + toggleType={ToggleType.BUTTON} + type={Type.PRIM} + toggleStatus={toggleStatus} + text={buttonText} + color={color} + icon={this.Icon(color)!} label={this.label} - onPointerDown={() => script.script.run({ self: this.rootDoc, value: !toggleStatus, _readOnly_: false })} + onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })} /> - ) + ); } /** @@ -344,28 +330,24 @@ export class FontIconBox extends DocComponent<ButtonProps>() { const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const tooltip: string = StrCast(this.rootDoc.toolTip); - return ( - <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label}/> - ) + return <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label} />; } @computed get editableText() { // Script for running the toggle const script = ScriptCast(this.rootDoc.script); // Function to run the script - const checkResult = script?.script.run({ value: '', _readOnly_: true }).result; + const checkResult = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + + const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: false }).result; + + return <EditableText editing={false} setEditing={(editing: boolean) => {}} />; - const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ value, _readOnly_: false }).result; - - return <EditableText - editing={false} setEditing={(editing: boolean) => {}} - /> - return ( <div className="menuButton editableText"> <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} /> <div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}> - <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} /> + <EditableView GetValue={() => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} /> </div> </div> ); @@ -403,7 +385,8 @@ export class FontIconBox extends DocComponent<ButtonProps>() { case ButtonType.ClickButton: case ButtonType.ToolButton: button = ( - <IconButton tooltip={tooltip} onPointerDown={() => onClickScript?.script.run({ _readOnly_: false })} color={color} icon={this.Icon(color)!} label={this.label}/> + <IconButton tooltip={tooltip} + color={color} icon={this.Icon(color)!} label={this.label}/> ); break; case ButtonType.TextButton: @@ -412,7 +395,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { ); break; case ButtonType.MenuButton: button = ( - <IconButton tooltip={tooltip} onPointerDown={() => onClickScript?.script.run({ self: this.rootDoc, _readOnly_: false })} tooltipPlacement='right' size={Size.LARGE} color={color} icon={this.Icon(color)!} label={this.label}/> + <IconButton tooltip={tooltip} onPointerDown={() => onClickScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false })} tooltipPlacement='right' size={Size.LARGE} color={color} icon={this.Icon(color)!} label={this.label}/> ); break; } diff --git a/src/client/views/nodes/LinkBox.scss b/src/client/views/nodes/LinkBox.scss index b5b8e660f..767f0291b 100644 --- a/src/client/views/nodes/LinkBox.scss +++ b/src/client/views/nodes/LinkBox.scss @@ -1,3 +1,7 @@ -.linkBox-container-interactive { +.linkBox-container-interactive { pointer-events: all; -}
\ No newline at end of file + width: 100%; +} +.linkBox-container { + width: 100%; +} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index b4fb7a44e..d5ad128fe 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -17,6 +17,7 @@ import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; import React = require('react'); +import { Transform } from '../../../util/Transform'; export class DashFieldView { dom: HTMLDivElement; // container for label and value @@ -113,6 +114,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna componentWillUnmount() { this._reactionDisposer?.(); } + return100 = () => 100; // set the display of the field's value (checkbox for booleans, span of text for strings) @computed get fieldValueContent() { @@ -123,7 +125,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna col={0} deselectCell={emptyFunction} selectCell={emptyFunction} - maxWidth={this.props.hideKey ? undefined : () => 100} + maxWidth={this.props.hideKey ? undefined : this.return100} columnWidth={this.props.hideKey ? () => this.props.tbox.props.PanelWidth() - 20 : returnZero} selectedCell={() => [this._dashDoc!, 0]} fieldKey={this._fieldKey} @@ -135,6 +137,8 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna allowCRs={true} oneLine={!this._expanded} finishEdit={action(() => (this._expanded = false))} + transform={Transform.Identity} + menuTarget={null} /> </div> ); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 0fd93868a..1319a236d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -26,6 +26,7 @@ import { Annotation } from './Annotation'; import './PDFViewer.scss'; import React = require('react'); import { GPTPopup } from './GPTPopup/GPTPopup'; +import { InkingStroke } from '../InkingStroke'; const PDFJSViewer = require('pdfjs-dist/web/pdf_viewer'); const pdfjsLib = require('pdfjs-dist'); const _global = (window /* browser */ || global) /* node */ as any; @@ -519,7 +520,8 @@ export class PDFViewer extends React.Component<IViewerProps> { childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc) || this.props.isContentActive() === false) return 'none'; - return 'all'; + const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString; + return isInk ? 'visiblePainted' : 'all'; } return this.props.styleProvider?.(doc, props, property); }; @@ -537,7 +539,7 @@ export class PDFViewer extends React.Component<IViewerProps> { NativeWidth={returnZero} NativeHeight={returnZero} setContentView={emptyFunction} // override setContentView to do nothing - pointerEvents={SnappingManager.GetIsDragging() && this.props.isContentActive() ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it. + pointerEvents={this.props.isContentActive() && (SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it. childPointerEvents={this.props.isContentActive() !== false ? 'all' : 'none'} // but freeform children need to get events to allow text editing, etc renderDepth={this.props.renderDepth + 1} isAnnotationOverlay={true} diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 79f41fe9d..ec4252eb8 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -134,14 +134,16 @@ export class TopBar extends React.Component { @computed get topbarRight() { return ( <div className="topbar-right"> - <Button - text={GetEffectiveAcl(Doc.ActiveDashboard) === AclAdmin ? 'Share' : 'View Original'} - type={Type.TERT} - color={this.variantColor} - onClick={() => { - SharingManager.Instance.open(undefined, Doc.ActiveDashboard); - }} - /> + {Doc.ActiveDashboard ? + <Button + text={GetEffectiveAcl(Doc.ActiveDashboard) === AclAdmin ? 'Share' : 'View Original'} + type={Type.TERT} + color={this.variantColor} + onClick={() => { + SharingManager.Instance.open(undefined, Doc.ActiveDashboard); + }} + /> + : null } <IconButton tooltip={"Issue Reporter ⌘I"} size={Size.SMALL} color={this.color} onClick={ReportManager.Instance.open} icon={<FaBug />} /> <IconButton tooltip={"Documentation ⌘D"} size={Size.SMALL} color={this.color} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} /> <IconButton tooltip={"Settings ⌘⇧S"} size={Size.SMALL} color={this.color} onClick={SettingsManager.Instance.open} icon={<FontAwesomeIcon icon="cog" />} /> |
