diff options
author | bobzel <zzzman@gmail.com> | 2023-08-27 13:37:45 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-08-27 13:37:45 -0400 |
commit | e566cdb001da320b5ee3f7fa60d96b7a09a195c3 (patch) | |
tree | 3d4373ede28da858ae964edffa8539961f148471 | |
parent | 0332a80329328e39c244623d5090331b83df339c (diff) | |
parent | 6d60b14e109e527ddc7a096af858cbc05dab3480 (diff) |
Merge branch 'master' into data-visualization-sarah
-rw-r--r-- | package-lock.json | 39 | ||||
-rw-r--r-- | src/.DS_Store | bin | 10244 -> 10244 bytes | |||
-rw-r--r-- | src/client/documents/Documents.ts | 167 | ||||
-rw-r--r-- | src/client/views/DashboardView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/FilterPanel.scss | 66 | ||||
-rw-r--r-- | src/client/views/FilterPanel.tsx | 307 | ||||
-rw-r--r-- | src/client/views/MainView.scss | 8 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/Palette.tsx | 69 | ||||
-rw-r--r-- | src/client/views/PropertiesSection.tsx | 3 | ||||
-rw-r--r-- | src/client/views/PropertiesView.scss | 14 | ||||
-rw-r--r-- | src/client/views/PropertiesView.tsx | 19 | ||||
-rw-r--r-- | src/fields/Doc.ts | 18 | ||||
-rw-r--r-- | src/fields/IconField.ts | 26 | ||||
-rw-r--r-- | src/fields/PresField.ts | 6 | ||||
-rw-r--r-- | src/mobile/MobileInterface.tsx | 1 |
16 files changed, 559 insertions, 190 deletions
diff --git a/package-lock.json b/package-lock.json index 00410e3be..250ac5f8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10445,16 +10445,6 @@ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "d3": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz", @@ -11835,28 +11825,6 @@ "is-symbol": "^1.0.2" } }, - "es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "dev": true, - "requires": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, "es6-promise": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", @@ -11868,7 +11836,6 @@ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { - "d": "^1.0.1", "ext": "^1.1.2" } }, @@ -27681,12 +27648,6 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/src/.DS_Store b/src/.DS_Store Binary files differindex 3005fd3b3..c363efb13 100644 --- a/src/.DS_Store +++ b/src/.DS_Store diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7f3309ea8..1186446e1 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -75,6 +75,8 @@ export class FInfo { readOnly: boolean = false; fieldType?: string = ''; values?: Field[]; + + filterable?: boolean = true; // format?: string; // format to display values (e.g, decimal places, $, etc) // parse?: ScriptField; // parse a value from a string constructor(d: string, readOnly?: boolean) { @@ -85,50 +87,61 @@ export class FInfo { class BoolInfo extends FInfo { fieldType? = 'boolean'; values?: boolean[] = [true, false]; + constructor(d: string, filterable?: boolean) { + super(d); + this.filterable = filterable; + } } class NumInfo extends FInfo { fieldType? = 'number'; values?: number[] = []; - constructor(d: string, readOnly?: boolean, values?: number[]) { + constructor(d: string, filterable?: boolean, readOnly?: boolean, values?: number[]) { super(d, readOnly); this.values = values; + this.filterable = filterable; } } class StrInfo extends FInfo { fieldType? = 'string'; values?: string[] = []; - constructor(d: string, readOnly?: boolean, values?: string[]) { + constructor(d: string, filterable?: boolean, readOnly?: boolean, values?: string[]) { super(d, readOnly); this.values = values; + this.filterable = filterable; } } class DocInfo extends FInfo { fieldType? = 'Doc'; values?: Doc[] = []; - constructor(d: string, values?: Doc[]) { + constructor(d: string, filterable?: boolean, values?: Doc[]) { super(d, true); this.values = values; + this.filterable = filterable; } } class DimInfo extends FInfo { fieldType? = 'enumeration'; values? = [DimUnit.Pixel, DimUnit.Ratio]; readOnly = false; + filterable = false; } class PEInfo extends FInfo { fieldType? = 'enumeration'; values? = ['all', 'none']; readOnly = false; + filterable = false; } class DAInfo extends FInfo { fieldType? = 'enumeration'; values? = ['embed', 'copy', 'move', 'same', 'proto', 'none']; readOnly = false; + filterable = false; } class CTypeInfo extends FInfo { fieldType? = 'enumeration'; values? = Array.from(Object.keys(CollectionViewType)); readOnly = false; + filterable = false; } class DTypeInfo extends FInfo { fieldType? = 'enumeration'; @@ -138,10 +151,16 @@ class DTypeInfo extends FInfo { class DateInfo extends FInfo { fieldType? = 'date'; values?: DateField[] = []; + filterable = true; +} +class ListInfo extends FInfo { + fieldType? = 'list'; + values?: List<any>[] = []; } type BOOLt = BoolInfo | boolean; type NUMt = NumInfo | number; type STRt = StrInfo | string; +type LISTt = ListInfo | List<any>; type DOCt = DocInfo | Doc; type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio; type PEVt = PEInfo | 'none' | 'all'; @@ -151,26 +170,26 @@ type DATEt = DateInfo | number; type DTYPEt = DTypeInfo | string; export class DocumentOptions { // coordinate and dimensions depending on view - x?: NUMt = new NumInfo('x coordinate of document in a freeform view'); - y?: NUMt = new NumInfo('y coordinage of document in a freeform view'); - z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]); - _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height"); + x?: NUMt = new NumInfo('x coordinate of document in a freeform view', false); + y?: NUMt = new NumInfo('y coordinage of document in a freeform view', false); + z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, false, [1, 0]); + _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", false); _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units"); - latitude?: NUMt = new NumInfo('latitude coordinate for map views'); - longitude?: NUMt = new NumInfo('longitude coordinate for map views'); + latitude?: NUMt = new NumInfo('latitude coordinate for map views', false); + longitude?: NUMt = new NumInfo('longitude coordinate for map views', false); map?: STRt = new StrInfo('text location of map'); - map_type?: STRt = new StrInfo('type of map view'); - map_zoom?: NUMt = new NumInfo('zoom of a map view'); - _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)'); - _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden'); + map_type?: STRt = new StrInfo('type of map view', false); + map_zoom?: NUMt = new NumInfo('zoom of a map view', false); + _timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)', false); + _timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden', false); _width?: NUMt = new NumInfo('displayed width of a document'); _height?: NUMt = new NumInfo('displayed height of document'); - data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)'); - data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)'); - linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)'); - _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)'); - _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)'); - _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers'); + data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)', false); + data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)', false); + linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)', false); + _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)', false); + _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)', false); + _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); 'acl-Guest'?: STRt = new StrInfo("permissions granted to users logged in as 'guest' (either view, or private)"); // public permissions @@ -178,30 +197,30 @@ export class DocumentOptions { type?: DTYPEt = new DTypeInfo('type of document', true); type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection - title?: STRt = new StrInfo('title of document'); + title?: STRt = new StrInfo('title of document', true); caption?: RichTextField; author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable author_date?: DATEt = new DateInfo('date the document was created', true); - annotationOn?: DOCt = new DocInfo('document annotated by this document'); - embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument'); - color?: STRt = new StrInfo('foreground color data doc'); - hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection'); - backgroundColor?: STRt = new StrInfo('background color for data doc'); - opacity?: NUMt = new NumInfo('document opacity'); - viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters'); - dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc'); + annotationOn?: DOCt = new DocInfo('document annotated by this document', false); + embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false); + color?: STRt = new StrInfo('foreground color data doc', false); + hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false); + backgroundColor?: STRt = new StrInfo('background color for data doc', false); + opacity?: NUMt = new NumInfo('document opacity', false); + viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters', false); + dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc', false); _undoIgnoreFields?: List<string>; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)' undoIgnoreFields?: List<string>; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)' - _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title'); - _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes'); + _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title', false); + _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes', false); _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume'); _lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged"); _lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed'); layout?: string | Doc; // default layout string or template document - layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document'); - layout_explainer?: STRt = new StrInfo('explanation displayed at top of a collection to describe its purpose'); - layout_headerButton?: DOCt = new DocInfo('the (button) Doc to display at the top of a collection.'); + layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document', false); + layout_explainer?: STRt = new StrInfo('explanation displayed at top of a collection to describe its purpose', false); + layout_headerButton?: DOCt = new DocInfo('the (button) Doc to display at the top of a collection.', false); layout_disableBrushing?: BOOLt = new BoolInfo('whether to suppress border highlighting'); layout_unrendered?: BOOLt = new BoolInfo('denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)'); layout_hideOpenButton?: BOOLt = new BoolInfo('whether to hide the open full screen button when selected'); @@ -213,33 +232,33 @@ export class DocumentOptions { layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected'); layout_borderRounding?: string; layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow - layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents'); + layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents', false); _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); - _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document'); - _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds'); + _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); + _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)'); _layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content'); - _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition'); + _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); _layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button'); _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix) _layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts'); _layout_showCaption?: string; // which field to display in the caption area. leave empty to have no caption _chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden'); - _gridGap?: NUMt = new NumInfo('gap between items in masonry view'); - _xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts'); - _yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts'); - _xPadding?: NUMt = new NumInfo('x padding'); - _yPadding?: NUMt = new NumInfo('y padding'); + _gridGap?: NUMt = new NumInfo('gap between items in masonry view', false); + _xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts', false); + _yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts', false); + _xPadding?: NUMt = new NumInfo('x padding', false); + _yPadding?: NUMt = new NumInfo('y padding', false); _singleLine?: boolean; // whether label box is restricted to one line of text _createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents - _columnWidth?: NUMt = new NumInfo('width of table column'); + _columnWidth?: NUMt = new NumInfo('width of table column', false); _columnsHideIfEmpty?: BOOLt = new BoolInfo('whether stacking view column headings should be hidden'); - _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', true); - _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', true); - icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', true); - icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', true); + _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', false, true); + _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', false, true); + icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', false, true); + icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', false, true); _text_fontSize?: string; _text_fontFamily?: string; _text_fontWeight?: string; @@ -247,11 +266,11 @@ export class DocumentOptions { infoWindowOpen?: BOOLt = new BoolInfo('whether info window corresponding to pin is open (on MapDocuments)'); _carousel_index?: NUMt = new NumInfo('which item index the carousel viewer is showing'); - _label_minFontSize?: NUMt = new NumInfo('minimum font size for labelBoxes'); - _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes'); - stroke_width?: NUMt = new NumInfo('width of an ink stroke'); - icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)'); - mediaState?: STRt = new StrInfo('status of audio/video media document: "pendingRecording", "recording", "paused", "playing"'); + _label_minFontSize?: NUMt = new NumInfo('minimum font size for labelBoxes', false); + _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes', false); + stroke_width?: NUMt = new NumInfo('width of an ink stroke', false); + icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)', false); + mediaState?: STRt = new StrInfo('status of audio/video media document: "pendingRecording", "recording", "paused", "playing"', false); recording?: BOOLt = new BoolInfo('whether WebCam is recording or not'); autoPlayAnchors?: BOOLt = new BoolInfo('whether to play audio/video when an anchor is clicked in a stackedTimeline.'); dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.'); @@ -269,7 +288,7 @@ export class DocumentOptions { contextMenuIcons?: List<string>; childFilters_boolean?: string; childFilters?: List<string>; - childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children. 0 - means height can be no bigger than width'); + childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children. 0 - means height can be no bigger than width', false); childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view) childLayoutString?: string; // template string for collection to use to render its children childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active'); @@ -281,12 +300,12 @@ export class DocumentOptions { childContextMenuIcons?: List<string>; targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc) - lastFrame?: NUMt = new NumInfo('the last frame of a frame-based collection (e.g., progressive slide)'); - activeFrame?: NUMt = new NumInfo('the active frame of a document in a frame base collection'); - appearFrame?: NUMt = new NumInfo('the frame in which the document appears'); - _currentFrame?: NUMt = new NumInfo('the current frame of a frame-based collection (e.g., progressive slide)'); + lastFrame?: NUMt = new NumInfo('the last frame of a frame-based collection (e.g., progressive slide)', false); + activeFrame?: NUMt = new NumInfo('the active frame of a document in a frame base collection', false); + appearFrame?: NUMt = new NumInfo('the frame in which the document appears', false); + _currentFrame?: NUMt = new NumInfo('the current frame of a frame-based collection (e.g., progressive slide)', false); - isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true); + isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', false); isBaseProto?: BOOLt = new BoolInfo('is doc a base level prototype for data documents as opposed to data documents which are prototypes for layout documents. base protos are not cloned during a deep'); isTemplateForField?: string; // the field key for which the containing document is a rendering template isTemplateDoc?: BOOLt = new BoolInfo('is the document a template for creating other documents'); @@ -295,26 +314,28 @@ export class DocumentOptions { _isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label'); _isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target'); - config_latitude?: NUMt = new NumInfo('latitude of a map'); // latitude of a map - config_longitude?: NUMt = new NumInfo('longitude of map'); // longitude of map - config_map_zoom?: NUMt = new NumInfo('zoom of map'); // zoom of map - config_map_type?: string; - config_map?: string; - config_panX?: NUMt = new NumInfo('panX saved as a view spec'); - config_panY?: NUMt = new NumInfo('panY saved as a view spec'); - config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec'); - presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document'); - presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view'); - presentation_zoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out'); + config_latitude?: NUMt = new NumInfo('latitude of a map', false); + config_longitude?: NUMt = new NumInfo('longitude of map', false); + config_map_zoom?: NUMt = new NumInfo('zoom of map', false); + config_map_type?: STRt = new StrInfo('map view type (e.g, aerial)', false); + config_map?: STRt = new StrInfo('text location of map', false); + config_panX?: NUMt = new NumInfo('panX saved as a view spec', false); + config_panY?: NUMt = new NumInfo('panY saved as a view spec', false); + config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec', false); + presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document', false); + presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view', false); + presentation_zoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out', false); data?: any; data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); columnHeaders?: List<SchemaHeaderField>; // headers for stacking views schemaHeaders?: List<SchemaHeaderField>; // headers for schema view - dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)'); + dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)', false); icon?: string; // icon used by fonticonbox to render button noteType?: string; + // STOPPING HERE + // freeform properties _freeform_backgroundGrid?: BOOLt = new BoolInfo('whether background grid is shown on freeform collections'); _freeform_scale?: NUMt = new NumInfo('how much a freeform view has been scaled (zoomed)'); @@ -382,9 +403,9 @@ export class DocumentOptions { cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc; dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group'); dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)'); - dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true); - dragFactory?: DOCt = new DocInfo('document to create when dragging with a suitable onDragStart script'); - clickFactory?: DOCt = new DocInfo('document to create when clicking on a button with a suitable onClick script'); + dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', false, true); + dragFactory?: DOCt = new DocInfo('document to create when dragging with a suitable onDragStart script', false); + clickFactory?: DOCt = new DocInfo('document to create when clicking on a button with a suitable onClick script', false); onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop target?: Doc; // available for use in scripts. used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script) diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 231a2d5fb..5d7fc8835 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -402,6 +402,7 @@ export class DashboardView extends React.Component { backgroundColor: background, title: `Untitled Tab 1`, }; + const title = name ? name : `Dashboard ${dashboardCount}`; const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); diff --git a/src/client/views/FilterPanel.scss b/src/client/views/FilterPanel.scss index 4f0460659..d6d2956aa 100644 --- a/src/client/views/FilterPanel.scss +++ b/src/client/views/FilterPanel.scss @@ -135,7 +135,7 @@ .filterBox-addFilter { width: 120px; - background-color: #e9e9e9; + backgroundcolor: #e9e9e9; border-radius: 12px; padding: 5px; margin: 5px; @@ -156,7 +156,7 @@ right: 0; top: 0; z-index: 1; - // background-color: #9f9f9f; + // background-color: #9f9f9f; .filterBox-tree { z-index: 0; @@ -191,22 +191,60 @@ } } +.filterBox-facetHeader { + display: flex; + align-items: center; + // float:right; + .filterBox-facetHeader-collapse { + // float: right; + // justify-items: right; + // align-items: flex-end; + margin-left: auto; + // margin-right: 9px; -.filterBox-facetHeader{ - display: flex; - align-items: center; - // float:right; - - .filterBox-facetHeader-collapse{ float: right; - justify-items: right; - align-items: flex-end; - margin-left: auto; - margin-right: 9px; + font-size: 16; } + .filterBox-facetHeader-remove { + // margin-left: auto; + float: right; + font-size: 16; + font-weight: bold; + } } - - +.filterbox-collpasedAndActive { + // left:100px; + text-indent: 18px; + // background-color: pink; + font-size: 12px; + font-weight: bold; +} + +.sliderBox-outerDiv { + display: inline-block; + vertical-align: middle; +} + +// .sliderBox-outerDiv { +// width: 30%;// width: calc(100% - 14px); // 14px accounts for handles that are at the max value of the slider that would extend outside the box +// height: 40; // height: 100%; +// border-radius: inherit; +// display: flex; +// flex-direction: column; +// position: relative; +// // background-color: yellow; +// .slider-tracks { +// top: 7px; +// position: relative; +// } +// .slider-ticks { +// position: relative; +// } +// .slider-handles { +// top: 7px; +// position: relative; +// } +// } diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index 63bd01b19..11c2fc86c 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -2,6 +2,7 @@ import React = require('react'); import { action, computed, observable, ObservableMap } from 'mobx'; import { observer } from 'mobx-react'; import Select from 'react-select'; +import { Checkbox, Tooltip } from '@material-ui/core'; import { Doc, DocListCast, Field, StrListCast } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; import { StrCast } from '../../fields/Types'; @@ -11,14 +12,21 @@ import './FilterPanel.scss'; import { FieldView } from './nodes/FieldView'; import { SearchBox } from './search/SearchBox'; import { undoable } from '../util/UndoManager'; -import { AiOutlineMinusSquare } from 'react-icons/ai'; +import { AiOutlineMinusSquare, AiOutlinePlusSquare } from 'react-icons/ai'; import { CiCircleRemove } from 'react-icons/ci'; +import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider'; +import { TooltipRail, Handle, Tick, Track } from './nodes/SliderBox-components'; +import { DocumentOptions, FInfo } from '../documents/Documents'; +import { string32 } from 'pdfjs-dist/types/src/shared/util'; interface filterProps { rootDoc: Doc; } + @observer export class FilterPanel extends React.Component<filterProps> { + private _documentOptions: DocumentOptions = new DocumentOptions(); + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FilterPanel, fieldKey); } @@ -43,6 +51,7 @@ export class FilterPanel extends React.Component<filterProps> { if (targetDoc) { SearchBox.foreachRecursiveDoc([this.targetDoc], (depth, doc) => allDocs.add(doc)); } + console.log('this is all Docs' + Array.from(allDocs)); return Array.from(allDocs); } @@ -58,23 +67,56 @@ export class FilterPanel extends React.Component<filterProps> { .filter(key => key[0]) .filter(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode) .sort(); + + // console.log('THIS IS HERE ' + Doc.UserDoc().color + 'space ' + Doc.UserDoc().color); noviceFields.forEach(key => sortedKeys.splice(sortedKeys.indexOf(key), 1)); + + console.log('this is novice fields ' + noviceFields + 'and this is sorted Keys ' + sortedKeys); + return [...noviceFields, ...sortedKeys]; } + @computed get rangeFilters() { + return StrListCast(this.targetDoc?._childFiltersByRanges).filter((filter, i) => !(i % 3)); + } + /** - * The current attributes selected to filter based on + * activeFilters( ) -- all filters that currently have a filter set on them in this document (ranges, and others) + * ["#tags::bob::check", "tags::joe::check", "width", "height"] */ @computed get activeFilters() { - return StrListCast(this.targetDoc?._childFilters); + return StrListCast(this.targetDoc?._childFilters).concat(this.rangeFilters); } + @computed get mapActiveFiltersToFacets() { + const filters = new Map<string, string>(); + //this.targetDoc.docFilters + this.activeFilters.map(filter => filters.set(filter.split(Doc.FilterSep)[1], filter.split(Doc.FilterSep)[0])); + return filters; + } + + // + // activeFacetHeaders() - just the facet names, not the rest of the filter + // + // this wants to return all the filter facets that have an existing filter set on them in order to show them in the rendered panel + // this set may overlap the selectedFilters + // if the components reloads, these will still exist and be shown + + // ["#tags", "width", "height"] + // + + @computed get activeFacetHeaders() { + const activeHeaders = new Array(); + this.activeFilters.map(filter => activeHeaders.push(filter.split(Doc.FilterSep)[0])); + + return activeHeaders; + } /** * @returns a string array of the current attributes */ - @computed get currentFacets() { - return this.activeFilters.map(filter => filter.split(Doc.FilterSep)[0]); - } + // @computed get currentFacets() { + // return this.activeFilters.map(filter => filter.split(Doc.FilterSep)[0]); + // } gatherFieldValues(childDocs: Doc[], facetKey: string) { const valueSet = new Set<string>(); @@ -86,6 +128,7 @@ export class FilterPanel extends React.Component<filterProps> { newarray = []; subDocs.forEach(t => { const facetVal = t[facetKey]; + // console.log("facetVal " + facetVal) if (facetVal instanceof RichTextField || typeof facetVal === 'string') rtFields++; facetVal !== undefined && valueSet.add(Field.toString(facetVal as Field)); (facetVal === true || facetVal == false) && valueSet.add(Field.toString(!facetVal)); @@ -99,6 +142,7 @@ export class FilterPanel extends React.Component<filterProps> { } // } // }); + return { strings: Array.from(valueSet.keys()), rtFields }; } @@ -107,40 +151,87 @@ export class FilterPanel extends React.Component<filterProps> { Doc.setDocRangeFilter(this.targetDoc, filterName, undefined); }; - @observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>(); - @computed get activeFacets() { - const facets = new Map<string, 'text' | 'checkbox' | 'slider' | 'range'>(this._chosenFacets); - StrListCast(this.targetDoc?._childFilters).map(filter => facets.set(filter.split(Doc.FilterSep)[0], filter.split(Doc.FilterSep)[2] === 'match' ? 'text' : 'checkbox')); - setTimeout(() => StrListCast(this.targetDoc?._childFilters).map(action(filter => this._chosenFacets.set(filter.split(Doc.FilterSep)[0], filter.split(Doc.FilterSep)[2] === 'match' ? 'text' : 'checkbox')))); - return facets; + // @observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>(); + @observable _chosenFacetsCollapse = new ObservableMap<string, boolean>(); + @observable _collapseReturnKeys = new Array(); + + // this computed function gets the active filters and maps them to their headers + + // + // activeRenderedFacetInfos() + // returns renderInfo for all user selected filters and for all existing filters set on the document + // Map("tags" => {"checkbox"}, + // "width" => {"rangs", domain:[1978,1992]}) + // + + @computed get activeRenderedFacetInfos() { + return new Set( + Array.from(new Set(Array.from(this._selectedFacetHeaders).concat(this.activeFacetHeaders))).map(facetHeader => { + const facetValues = this.gatherFieldValues(this.targetDocChildren, facetHeader); + + let nonNumbers = 0; + let minVal = Number.MAX_VALUE, + maxVal = -Number.MAX_VALUE; + facetValues.strings.map(val => { + const num = val ? Number(val) : Number.NaN; + if (Number.isNaN(num)) { + val && nonNumbers++; + } else { + minVal = Math.min(num, minVal); + maxVal = Math.max(num, maxVal); + } + }); + + if (facetHeader === 'text') { + return { facetHeader: facetHeader, renderType: 'text' }; + } else if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) { + const extendedMinVal = minVal - Math.min(1, Math.floor(Math.abs(maxVal - minVal) * 0.1)); + const extendedMaxVal = Math.max(minVal + 1, maxVal + Math.min(1, Math.ceil(Math.abs(maxVal - minVal) * 0.05))); + const ranged = Doc.readDocRangeFilter(this.targetDoc, facetHeader); // not the filter range, but the zooomed in range on the filter + return { facetHeader: facetHeader, renderType: 'range', domain: [extendedMinVal, extendedMaxVal], range: ranged ? ranged : [extendedMinVal, extendedMaxVal] }; + } else { + return { facetHeader: facetHeader, renderType: 'checkbox' }; + } + }) + ); } + + @observable _selectedFacetHeaders = new Set<string>(); + /** - * Responds to clicking the check box in the flyout menu + * user clicks on a filter facet because they want to see it. + * this adds this chosen filter to a set of user selected filters called: selectedFilters + * if this component reloads, then these filters will go away since they haven't been written to any Doc anywhere + * + * // this._selectedFacets.add(facetHeader); .. add to Set() not array */ + @action facetClick = (facetHeader: string) => { - if (!this.targetDoc) return; - const allCollectionDocs = this.targetDocChildren; - const facetValues = this.gatherFieldValues(this.targetDocChildren, facetHeader); + // just when someone chooses a facet - let nonNumbers = 0; - let minVal = Number.MAX_VALUE, - maxVal = -Number.MAX_VALUE; - facetValues.strings.map(val => { - const num = val ? Number(val) : Number.NaN; - if (Number.isNaN(num)) { - val && nonNumbers++; - } else { - minVal = Math.min(num, minVal); - maxVal = Math.max(num, maxVal); + this._selectedFacetHeaders.add(facetHeader); + + return; + }; + + @action + sortingCurrentFacetValues = (facetHeader: string) => { + this._collapseReturnKeys.splice(0); + + Array.from(this.activeRenderedFacetInfos.keys()).map(renderInfo => { + if (renderInfo.renderType === 'range' && renderInfo.facetHeader === facetHeader && renderInfo.range) { + this._collapseReturnKeys.push(renderInfo.range.map(number => number.toFixed(2))); } }); - if (facetHeader === 'text' || (facetValues.rtFields / allCollectionDocs.length > 0.1 && facetValues.strings.length > 20)) { - this._chosenFacets.set(facetHeader, 'text'); - } else if (facetHeader !== 'tags' && nonNumbers / facetValues.strings.length < 0.1) { - } else { - this._chosenFacets.set(facetHeader, 'checkbox'); + + for (var key of this.facetValues(facetHeader)) { + if (this.mapActiveFiltersToFacets.get(key)) { + this._collapseReturnKeys.push(key); + } } + + return <div className=" filterbox-collpasedAndActive">{this._collapseReturnKeys.join(', ')}</div>; }; facetValues = (facetHeader: string) => { @@ -168,7 +259,24 @@ export class FilterPanel extends React.Component<filterProps> { }; render() { - const options = this._allFacets.filter(facet => this.currentFacets.indexOf(facet) === -1).map(facet => ({ value: facet, label: facet })); + // console.log('this is frist one today ' + this._allFacets); + this._allFacets.forEach(element => console.log(element)); + // const options = Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => pair[1].filterable ).map(facet => value: facet, label: facet) //this._allFacets.filter(facet => this.activeFacetHeaders.indexOf(facet) === -1).map(facet => ({ value: facet, label: facet })); + // console.log('HEELLLLLL ' + DocumentOptions); + + let filteredOptions: string[] = ['author', 'tags', 'text', 'acl-Guest']; + + Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => { + if (pair[1].filterable) { + filteredOptions.push(pair[0]); + console.log('THIS IS FILTERABLE ALKDJFIIEII' + filteredOptions); + } + }); + + let options = filteredOptions.map(facet => ({ value: facet, label: facet })); + + // Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => console.log('this is first piar ' + pair[0] + ' this is second piar ' + pair[1].filterable)); + return ( <div className="filterBox-treeView"> <div className="filterBox-select"> @@ -188,29 +296,58 @@ export class FilterPanel extends React.Component<filterProps> { </div> <div className="filterBox-tree" key="tree"> - {Array.from(this.activeFacets.keys()).map(facetHeader => ( - <div> - <div className="filterBox-facetHeader"> - <div className="filterBox-facetHeader-Header"> </div> - {facetHeader.charAt(0).toUpperCase() + facetHeader.slice(1)} + {Array.from(this.activeRenderedFacetInfos.keys()).map( + ( + renderInfo // iterato over activeFacetRenderInfos ==> renderInfo which you can renderInfo.facetHeader + ) => ( + <div> + <div className="filterBox-facetHeader"> + <div className="filterBox-facetHeader-Header"> </div> + {renderInfo.facetHeader.charAt(0).toUpperCase() + renderInfo.facetHeader.slice(1)} + + <div + className="filterBox-facetHeader-collapse" + onClick={action(e => { + const collapseBoolValue = this._chosenFacetsCollapse.get(renderInfo.facetHeader); + this._chosenFacetsCollapse.set(renderInfo.facetHeader, !collapseBoolValue); + })}> + {this._chosenFacetsCollapse.get(renderInfo.facetHeader) ? <AiOutlinePlusSquare /> : <AiOutlineMinusSquare />} + </div> - <div className="filterBox-facetHeader-collapse"> - <AiOutlineMinusSquare /> - {/* <CiCircleRemove/> */} + <div + className="filterBox-facetHeader-remove" + onClick={action(e => { + for (var key of this.facetValues(renderInfo.facetHeader)) { + if (this.mapActiveFiltersToFacets.get(key)) { + Doc.setDocFilter(this.targetDoc, renderInfo.facetHeader, key, 'remove'); + } + } + this._selectedFacetHeaders.delete(renderInfo.facetHeader); + this._chosenFacetsCollapse.delete(renderInfo.facetHeader); + + if (renderInfo.domain) { + Doc.setDocRangeFilter(this.targetDoc, renderInfo.facetHeader, renderInfo.domain, 'remove'); + } + })}> + <CiCircleRemove />{' '} + </div> </div> - </div> - {this.displayFacetValueFilterUIs(this.activeFacets.get(facetHeader), facetHeader)} - </div> - ))} + {this._chosenFacetsCollapse.get(renderInfo.facetHeader) + ? this.sortingCurrentFacetValues(renderInfo.facetHeader) + : this.displayFacetValueFilterUIs(renderInfo.renderType, renderInfo.facetHeader, renderInfo.domain, renderInfo.range)} + {/* */} + </div> + ) + )} </div> </div> ); } - private displayFacetValueFilterUIs(type: string | undefined, facetHeader: string): React.ReactNode { - switch (type) { - case 'text': + private displayFacetValueFilterUIs(type: string | undefined, facetHeader: string, renderInfoDomain?: number[] | undefined, renderInfoRange?: number[]): React.ReactNode { + switch (type /* renderInfo.type */) { + case 'text': // if (this.chosenFacets.get(facetHeader) === 'text') return ( <input placeholder={ @@ -241,6 +378,82 @@ export class FilterPanel extends React.Component<filterProps> { </div> ); }); + + case 'range': + const domain = renderInfoDomain; + const range = renderInfoRange; + + if (range) { + console.log('this is info range ' + range[0] + ' , ' + range[1]); + } + + if (domain) { + console.log('this is info domain ' + domain[0] + ', ' + domain[1]); + + return ( + <> + {/* <div className="sliderBox-outerDiv-checkBox" style={{ float: 'left' }}> + <Checkbox color="primary" onChange={action(() => console.log('on change'))} /> + </div> */} + + <div className="sliderBox-outerDiv" style={{ width: '95%', height: 45, float: 'right' }}> + <Slider + mode={2} + step={Math.min(1, 0.1 * (domain[1] - domain[0]))} + domain={[domain[0], domain[1]]} // -1000, 1000 + rootStyle={{ position: 'relative', width: '100%' }} + onChange={values => Doc.setDocRangeFilter(this.targetDoc, facetHeader, values)} + values={renderInfoRange!}> + <Rail>{railProps => <TooltipRail {...railProps} />}</Rail> + <Handles> + {({ handles, activeHandleID, getHandleProps }) => ( + <div className="slider-handles"> + {handles.map((handle, i) => { + // const value = i === 0 ? defaultValues[0] : defaultValues[1]; + return ( + <div> + <Handle key={handle.id} handle={handle} domain={domain} isActive={handle.id === activeHandleID} getHandleProps={getHandleProps} /> + </div> + ); + })} + </div> + )} + </Handles> + <Tracks left={false} right={false}> + {({ tracks, getTrackProps }) => ( + <div className="slider-tracks"> + {tracks.map(({ id, source, target }) => ( + <Track key={id} source={source} target={target} disabled={false} getTrackProps={getTrackProps} /> + ))} + </div> + )} + </Tracks> + <Ticks count={5}> + {({ ticks }) => ( + <div className="slider-ticks"> + {ticks.map(tick => ( + <Tick key={tick.id} tick={tick} count={ticks.length} format={(val: number) => val.toString()} /> + ))} + </div> + )} + </Ticks> + </Slider> + </div> + </> + ); + } + + // case 'range' + // return <Slider ... + // return <slider domain={renderInfo.domain}> domain is number[] for min and max + // onChange = { ... Doc.setDocRangeFilter(this.targetDoc, facetHeader, [extendedMinVal, extendedMaxVal] ) } + // + // OR + + // return <div> + // <slider domain={renderInfo.domain}> // domain is number[] for min and max + // <dimain changing handles > + // <?div } } } diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index b3faff442..8a7f5132b 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -194,11 +194,11 @@ 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; - } + // .editable-title { + // background-color: linen; //$light-gray; + // } } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cbe06a9c0..c81bc70b8 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -813,9 +813,8 @@ export class MainView extends React.Component { {this.dockingContent} {this._hideUI ? null : ( - <div className="mainView-propertiesDragger" - key="props" onPointerDown={this.onPropertiesPointerDown} style={{ background: StrCast(Doc.UserDoc().userBackgroundColor), right: this.propertiesWidth() - 1}}> - <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={StrCast(Doc.UserDoc().userColor)} size="sm" /> + <div className="mainView-propertiesDragger" key="props" onPointerDown={this.onPropertiesPointerDown} style={{ background: SettingsManager.Instance.userBackgroundColor, right: this.propertiesWidth() - 1 }}> + <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? 'chevron-left' : 'chevron-right'} color={SettingsManager.Instance.userColor} size="sm" /> </div> )} <div className="properties-container" style={{ width: this.propertiesWidth() }}> diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx new file mode 100644 index 000000000..3ad28c418 --- /dev/null +++ b/src/client/views/Palette.tsx @@ -0,0 +1,69 @@ +import { IReactionDisposer, observable, reaction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../fields/Doc'; +import { NumCast } from '../../fields/Types'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils'; +import { Transform } from '../util/Transform'; +import { DocumentView } from './nodes/DocumentView'; +import './Palette.scss'; + +export interface PaletteProps { + x: number; + y: number; + thumb: number[]; + thumbDoc: Doc; +} + +@observer +export default class Palette extends React.Component<PaletteProps> { + private _selectedDisposer?: IReactionDisposer; + @observable private _selectedIndex: number = 0; + + componentDidMount = () => { + this._selectedDisposer = reaction( + () => NumCast(this.props.thumbDoc.selectedIndex), + i => (this._selectedIndex = i), + { fireImmediately: true } + ); + }; + + componentWillUnmount = () => { + this._selectedDisposer?.(); + }; + + render() { + return ( + <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}> + <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}> + <div className="palette-thumbContent" style={{ transform: `translate(-${this._selectedIndex * 50 + 10}px, 0px)` }}> + <DocumentView + Document={this.props.thumbDoc} + DataDoc={undefined} + addDocument={undefined} + addDocTab={returnFalse} + rootSelected={returnTrue} + pinToPres={emptyFunction} + removeDocument={undefined} + ScreenToLocalTransform={Transform.Identity} + PanelWidth={() => window.screen.width} + PanelHeight={() => window.screen.height} + renderDepth={0} + isDocumentActive={returnTrue} + isContentActive={emptyFunction} + focus={emptyFunction} + docViewPath={returnEmptyDoclist} + styleProvider={returnEmptyString} + whenChildContentsActiveChanged={emptyFunction} + bringToFront={emptyFunction} + docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} + /> + <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div> + </div> + </div> + </div> + ); + } +} diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx index 6fab0168b..b72e048df 100644 --- a/src/client/views/PropertiesSection.tsx +++ b/src/client/views/PropertiesSection.tsx @@ -49,7 +49,8 @@ export class PropertiesSection extends React.Component<PropertiesSectionProps> { this.props.setIsOpen(!this.props.isOpen); })} style={{ - background: this.props.isOpen ? this.variantColor : this.backgroundColor, + background: this.variantColor, + // this.props.isOpen ? this.variantColor : this.backgroundColor, color: this.color, }}> {this.props.title} diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index e3a481206..63b9b53c2 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -35,6 +35,20 @@ padding: 5px 10px; } + .propertiesView-propAndInfoGrouping { + display: flex; + } + + .propertiesView-info { + margin-top: 20; + margin-right: 10; + float: right; + font-size: 20; + path { + fill: white !important; + } + } + .propertiesView-sharing { //border-bottom: 1px solid black; //padding: 8.5px; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 9e054b876..9df04c862 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -191,7 +191,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { }); rows.push( - <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: 'white', textAlign: 'center' }}> + <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: SettingsManager.Instance.userBackgroundColor, textAlign: 'center' }}> <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} /> </div> ); @@ -564,13 +564,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { } @computed get currentType() { + // console.log("current type " + this.selectedDoc?.type) + const documentType = StrCast(this.selectedDoc?.type); var currentType: string = documentType; var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType); return ( <div> - <div className="propertiesView-wordType">Type</div> + Type + {/* <div className = "propertiesView-wordType">Type</div> */} <div className="currentType"> <div className="currentType-icon">{this.currentComponent}</div> @@ -1064,7 +1067,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width') )} {this.getNumber( - 'X Coordinate', + 'X', //'X Coordinate', ' px', -2000, 2000, @@ -1072,7 +1075,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { undoable((val: string) => !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord') )} {this.getNumber( - 'Y Coordinate', + 'Y', //'Y Coordinate', ' px', -2000, 2000, @@ -1663,19 +1666,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { <div className="propertiesView-propAndInfoGrouping"> <div className="propertiesView-title" style={{ width: this.props.width }}> Properties - <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/')}> - <IconButton icon={<FontAwesomeIcon icon={'info-circle'} />} color={StrCast(Doc.UserDoc().userColor)} /> + <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties')}> + <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.Instance.userColor} /> </div> </div> </div> <div className="propertiesView-name">{this.editableTitle}</div> <div className="propertiesView-type"> {this.currentType} </div> - {this.contextsSubMenu} + {this.optionsSubMenu} {this.linksSubMenu} {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : this.linkProperties} {this.inkSubMenu} - {this.optionsSubMenu} + {this.contextsSubMenu} {this.fieldsSubMenu} {isNovice ? null : this.sharingSubMenu} {isNovice ? null : this.filtersSubMenu} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 716039568..f242ab5be 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1461,21 +1461,37 @@ export namespace Doc { prevLayout === 'icon' && (doc.deiconifyLayout = undefined); doc.layout_fieldKey = deiconify || 'layout'; } - export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: number[]) { + export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: readonly number[], modifiers?: 'remove') { //, modifiers: 'remove' | 'set' if (!container) return; + const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []); + + + + for (let i = 0; i < childFiltersByRanges.length; i += 3) { if (childFiltersByRanges[i] === key) { + console.log("this is key inside childfilters by range " + key) childFiltersByRanges.splice(i, 3); + console.log("this is child filters by range " + childFiltersByRanges) break; } } if (range !== undefined) { + console.log("in doc.ts in set range filter") childFiltersByRanges.push(key); childFiltersByRanges.push(range[0].toString()); childFiltersByRanges.push(range[1].toString()); container._childFiltersByRanges = new List<string>(childFiltersByRanges); + console.log("this is child filters by range "+ childFiltersByRanges[0] + "," + childFiltersByRanges[1] + "," + childFiltersByRanges[2]) + console.log("this is new list " + container._childFiltersByRange) + } + + if (modifiers){ + childFiltersByRanges.splice(0,3) + container._childFiltersByRanges = new List<string>(childFiltersByRanges); } + console.log("this is child filters by range END"+ childFiltersByRanges[0] + "," + childFiltersByRanges[1] + "," + childFiltersByRanges[2]) } export const FilterSep = '::'; diff --git a/src/fields/IconField.ts b/src/fields/IconField.ts new file mode 100644 index 000000000..76c4ddf1b --- /dev/null +++ b/src/fields/IconField.ts @@ -0,0 +1,26 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString, ToString } from "./FieldSymbols"; + +@Deserializable("icon") +export class IconField extends ObjectField { + @serializable(primitive()) + readonly icon: string; + + constructor(icon: string) { + super(); + this.icon = icon; + } + + [Copy]() { + return new IconField(this.icon); + } + + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return "ICONfield"; + } +} diff --git a/src/fields/PresField.ts b/src/fields/PresField.ts new file mode 100644 index 000000000..f236a04fd --- /dev/null +++ b/src/fields/PresField.ts @@ -0,0 +1,6 @@ +//insert code here +import { ObjectField } from "./ObjectField"; + +export abstract class PresField extends ObjectField { + +}
\ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 584a7b432..c16a1c124 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -584,6 +584,7 @@ export class MobileInterface extends React.Component { y: 400, title: 'Collection ' + dashboardCount, }; + const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, 'row'); |