aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionSubView.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-02-10 19:07:20 -0500
committerbobzel <zzzman@gmail.com>2025-02-10 19:07:20 -0500
commitc9686eaebffb3547b7e0f20aec64754627af76ce (patch)
tree7ebf1c38323a8d7af554ba564acf95cfe79b7709 /src/client/views/collections/CollectionSubView.tsx
parentb72d018698ad1d2e713f0fcbef392d23bf1cf545 (diff)
parente93ca53af693fa1ec2186ca9417af122bb5e8e09 (diff)
updated from master
Diffstat (limited to 'src/client/views/collections/CollectionSubView.tsx')
-rw-r--r--src/client/views/collections/CollectionSubView.tsx66
1 files changed, 60 insertions, 6 deletions
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 48aac3a68..5e99bec39 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,7 +1,7 @@
import { action, computed, makeObservable, observable } from 'mobx';
import * as React from 'react';
import * as rp from 'request-promise';
-import { ClientUtils, returnFalse } from '../../../ClientUtils';
+import { ClientUtils, DashColor, returnFalse } from '../../../ClientUtils';
import CursorField from '../../../fields/CursorField';
import { Doc, DocListCast, GetDocFromUrl, GetHrefFromHTML, Opt, RTFIsFragment, StrListCast } from '../../../fields/Doc';
import { AclPrivate, DocData } from '../../../fields/DocSymbols';
@@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, DateCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
@@ -27,7 +27,16 @@ import { ViewBoxBaseComponent } from '../DocComponent';
import { FieldViewProps } from '../nodes/FieldView';
import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import { FlashcardPracticeUI } from './FlashcardPracticeUI';
-
+import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere';
+
+export enum docSortings {
+ Time = 'time',
+ Type = 'type',
+ Color = 'color',
+ Chat = 'chat',
+ Tag = 'tag',
+ None = '',
+}
export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently)
@@ -130,6 +139,17 @@ export function CollectionSubView<X>() {
@computed get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
+
+ addLinkedDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => {
+ const doc = toList(docsIn).lastElement();
+ const where = location.split(':')[0];
+ if (where === OpenWhere.lightbox && (this.childDocList?.includes(doc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(doc))) {
+ if (doc.hidden) doc.hidden = false;
+ if (!location.includes(OpenWhereMod.always)) return true;
+ }
+ return this._props.addDocTab(docsIn, location);
+ };
+
collectionFilters = () => this._focusFilters ?? StrListCast(this.Document._childFilters);
collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.Document._childFiltersByRanges, listSpec('string'), []);
// child filters apply to the descendants of the documents in this collection
@@ -138,6 +158,8 @@ export function CollectionSubView<X>() {
unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !ClientUtils.IsRecursiveFilter(f)) || [])];
childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this.Document._searchFilterDocs);
+
+ @observable docDraggedIndex = -1;
@computed.struct get childDocs() {
TraceMobx();
let rawdocs: (Doc | Promise<Doc>)[] = [];
@@ -154,8 +176,10 @@ export function CollectionSubView<X>() {
const templateRoot = this._props.TemplateDataDocument;
rawdocs = templateRoot && !this._props.isAnnotationOverlay ? [Doc.GetProto(templateRoot)] : [];
}
-
- const childDocs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this._props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc);
+ const childDocs = this.childSortedDocs(
+ rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && (this._props.ignoreUnrendered || !d.layout_unrendered)).map(d => d as Doc),
+ this.docDraggedIndex
+ );
const childDocFilters = this.childDocFilters();
const childFiltersByRanges = this.childDocRangeFilters();
@@ -202,6 +226,35 @@ export function CollectionSubView<X>() {
return docsforFilter;
}
+ childSortedDocs = (docsIn: Doc[], dragIndex: number) => {
+ const sortType = StrCast(this.Document[this._props.fieldKey + '_sort']) as docSortings;
+ const isDesc = BoolCast(this.Document[this._props.fieldKey + '_sort_desc']);
+ const docs = docsIn.slice();
+ if (sortType) {
+ docs.sort((docA, docB) => {
+ const [typeA, typeB] = (() => {
+ switch (sortType) {
+ default:
+ case docSortings.Type: return [StrCast(docA.type), StrCast(docB.type)];
+ case docSortings.Chat: return [NumCast(docA.chatIndex, 9999), NumCast(docB.chatIndex,9999)];
+ case docSortings.Time: return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
+ case docSortings.Color:return [DashColor(StrCast(docA.backgroundColor)).hsv().hue(), DashColor(StrCast(docB.backgroundColor)).hsv().hue()];
+ case docSortings.Tag: return [StrListCast(docA.tags).join(""), StrListCast(docB.tags).join("")];
+ }
+ })(); //prettier-ignore
+ return (typeA < typeB ? -1 : typeA > typeB ? 1 : 0) * (isDesc ? 1 : -1);
+ });
+ }
+ if (dragIndex !== -1) {
+ const draggedDoc = DragManager.docsBeingDragged[0];
+ const originalIndex = docs.findIndex(doc => doc === draggedDoc);
+
+ originalIndex !== -1 && docs.splice(originalIndex, 1);
+ draggedDoc && docs.splice(dragIndex, 0, draggedDoc);
+ }
+ return docs;
+ };
+
@action
protected async setCursorPosition(position: [number, number]) {
let ind;
@@ -519,6 +572,7 @@ export function CollectionSubView<X>() {
};
protected _sideBtnWidth = 35;
+ protected _sideBtnMaxPanelPct = 0.15;
@observable _filterFunc: ((doc: Doc) => boolean) | undefined = undefined;
/**
* How much the content of the collection is being scaled based on its nesting and its fit-to-width settings
@@ -529,7 +583,7 @@ export function CollectionSubView<X>() {
* This takes the desired screen space size and converts into collection coordinates. It then returns the smaller of the converted
* size or a fraction of the collection view.
*/
- @computed get maxWidgetSize() { return Math.min(this._sideBtnWidth * this.contentScaling, (this._props.fitWidth?.(this.Document) && this._props.PanelWidth() > NumCast(this.layoutDoc._width)? 1: 0.25) * NumCast(this.layoutDoc.width, 1)); } // prettier-ignore
+ @computed get maxWidgetSize() { return Math.min(this._sideBtnWidth * this.contentScaling, (this._props.fitWidth?.(this.Document) && this._props.PanelWidth() > NumCast(this.layoutDoc._width)? 1: this._sideBtnMaxPanelPct) * NumCast(this.layoutDoc.width, 1)); } // prettier-ignore
/**
* This computes a scale factor for UI elements so that they shrink and grow as the collection does in screen space.
* Note, the scale factor does not allow for elements to grow larger than their native screen space size.