diff options
-rw-r--r-- | src/client/views/StyleProvider.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.scss | 5 | ||||
-rw-r--r-- | src/client/views/collections/TreeView.scss | 11 | ||||
-rw-r--r-- | src/client/views/collections/TreeView.tsx | 74 |
4 files changed, 63 insertions, 29 deletions
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 5c10c2344..34418e170 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -213,7 +213,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps } export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, offIcon: IconProp, clickFunc?: () => void) { - return <div className={`styleProvider-treeView-icon${doc[field] ? "-active" : ""}`} + return <div title={field} className={`styleProvider-treeView-icon${doc[field] ? "-active" : ""}`} onClick={undoBatch(action((e: React.MouseEvent) => { e.stopPropagation(); clickFunc ? clickFunc() : (doc[field] = doc[field] ? undefined : true); diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index a8eee9c19..93523a6cf 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -1,5 +1,6 @@ @import "../global/globalCssVariables"; + .collectionTreeView-container { transform-origin: top left; height: 100%; @@ -31,9 +32,11 @@ width: unset; height: unset; } + &:hover { + cursor: ns-resize; + } } - .no-indent { padding-left: 0; width: max-content; diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 4707ebb80..b91737a1d 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -62,6 +62,17 @@ } } +.treeView-sorting { + position: absolute; + height: max-content; + pointer-events: none; + color: white; + border-radius: 4px; + font-size: 10px; +} +.treeView-container-active { + cursor: default; +} .treeView-container-outline-active .treeView-container-active { z-index: 100; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 9108acfcf..3a49297f8 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -79,6 +79,7 @@ export class TreeView extends React.Component<TreeViewProps> { static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>; static _openTitleScript: Opt<ScriptField | undefined>; static _openLevelScript: Opt<ScriptField | undefined>; + static _sortUIMap = [["up", "crimson", "↑"], ["down", "blue", "↓"], ["z", "green", "z"], ["x", "darkgray", '\u00A0\u00A0\u00A0']]; private _header: React.RefObject<HTMLDivElement> = React.createRef(); private _tref = React.createRef<HTMLDivElement>(); @observable _docRef: Opt<DocumentView>; @@ -156,6 +157,17 @@ export class TreeView extends React.Component<TreeViewProps> { docView.select(false); } } + @action + openLevel = (docView: DocumentView) => { + if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) { + this.treeViewOpen = !this.treeViewOpen; + } else { + // choose an appropriate alias or make one. --- choose the first alias that (1) user owns, (2) has no context field ... otherwise make a new alias + const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); + const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail); + this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), "lightbox"); + } + } constructor(props: any) { super(props); @@ -399,13 +411,16 @@ export class TreeView extends React.Component<TreeViewProps> { TraceMobx(); const expandKey = this.treeViewExpandedView; if (["links", "annotations", "aliases", this.fieldKey].includes(expandKey)) { + const sorting = StrCast(this.doc.treeViewSortCriterion); + const color = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[1]; + const label = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[2]; const key = (expandKey === "annotations" ? `${this.fieldKey}-` : "") + expandKey; const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key); const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't), // then the modification would be done here const ordering = StrCast(this.doc.treeViewSortCriterion); - if (ordering === "Z") { + if (ordering === "z") { const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering); doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000; docs.push(doc); @@ -418,24 +433,29 @@ export class TreeView extends React.Component<TreeViewProps> { const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); const docs = expandKey === "aliases" ? this.childAliases : expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs; let downX = 0, downY = 0; - const sortings = ["up", "down", "Z", undefined]; + const sortings = this.props.treeView.rootDoc === Doc.UserDoc().myFilesystem ? ["up", "down", "x"] : ["up", "down", "z", "x"]; const curSort = Math.max(0, sortings.indexOf(Cast(this.doc.treeViewSortCriterion, "string", null))); - return <ul key={expandKey + "more"} title={"sort: " + sortings[curSort]} className={this.doc.treeViewHideTitle ? "no-indent" : ""} - onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }} - onClick={(e) => { - if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortings[(curSort + 1) % sortings.length]); - e.stopPropagation(); - } - }}> - {!docs ? (null) : - TreeView.GetChildElements(docs, this.props.treeView, this, this.layoutDoc, - this.dataDoc, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move, - StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform, - this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, - [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged, - this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems())} - </ul >; + return <> + {!docs?.length ? (null) : <div className={'treeView-sorting'} style={{ background: color }} > + {label} + </div>} + <ul key={expandKey + "more"} title="click to change sort order" className={this.doc.treeViewHideTitle ? "no-indent" : ""} + onPointerDown={e => { downX = e.clientX; downY = e.clientY; e.stopPropagation(); }} + onClick={(e) => { + if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { + !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortings[(curSort + 1) % sortings.length]); + e.stopPropagation(); + } + }}> + {!docs ? (null) : + TreeView.GetChildElements(docs, this.props.treeView, this, this.layoutDoc, + this.dataDoc, this.props.containerCollection, this.props.prevSibling, addDoc, remDoc, this.move, + StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.titleStyleProvider, this.props.ScreenToLocalTransform, + this.props.isContentActive, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, + [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenChildContentsActiveChanged, + this.props.dontRegisterView, emptyFunction, emptyFunction, this.childContextMenuItems())} + </ul > + </>; } else if (this.treeViewExpandedView === "fields") { return <ul key={this.doc[Id] + this.doc.title}> <div style={{ display: "inline-block" }} > @@ -497,7 +517,7 @@ export class TreeView extends React.Component<TreeViewProps> { const data = () => this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : ""; const aliases = () => this.props.treeView.dashboardMode ? "" : "aliases"; const fields = () => Doc.UserDoc().noviceMode ? "" : "fields"; - const layout = (this.props.treeView.dashboardMode && Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"]; + const layout = (Doc.UserDoc().noviceMode) || this.doc.viewType === CollectionViewType.Docking ? [] : ["layout"]; return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m); } @action @@ -512,9 +532,9 @@ export class TreeView extends React.Component<TreeViewProps> { @computed get headerElements() { return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? (null) : <> - {this.doc.hideContextMenu ? (null) : <FontAwesomeIcon key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />} + {this.doc.hideContextMenu ? (null) : <FontAwesomeIcon title="context menu" key="bars" icon="bars" size="sm" onClick={e => { this.showContextMenu(e); e.stopPropagation(); }} />} {this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? (null) : - <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}> + <span className="collectionTreeView-keyHeader" title="type of expanded data" key={this.treeViewExpandedView} onPointerDown={this.expandNextviewType}> {this.treeViewExpandedView} </span>} </>; @@ -771,9 +791,9 @@ export class TreeView extends React.Component<TreeViewProps> { } @computed get renderBorder() { - const sorting = this.doc[`${this.fieldKey}-sortCriterion`]; - return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`} - style={{ borderColor: sorting === undefined ? undefined : sorting === "up" ? "crimson" : sorting === "down" ? "blue" : "green" }}> + const sorting = StrCast(this.doc.treeViewSortCriterion); + const color = (TreeView._sortUIMap.find((sortUIfields) => sortUIfields[0] === sorting) ?? TreeView._sortUIMap.lastElement())[1]; + return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`} style={{ borderColor: color }}> {!this.treeViewOpen ? (null) : this.renderContent} </div>; } @@ -822,9 +842,9 @@ export class TreeView extends React.Component<TreeViewProps> { }; docs.sort(function (d1, d2): 0 | 1 | -1 { const a = (criterion === "up" ? d2 : d1); - const b = (criterion === "up" ? d1 : d2); - const first = a[criterion === "Z" ? "zIndex" : "title"]; - const second = b[criterion === "Z" ? "zIndex" : "title"]; + const b = (criterion === "down" ? d1 : d2); + const first = a[criterion === "z" ? "zIndex" : "title"]; + const second = b[criterion === "z" ? "zIndex" : "title"]; if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1; if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second); return criterion ? 1 : -1; |