aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-01-28 12:02:37 -0500
committerbobzel <zzzman@gmail.com>2025-01-28 12:02:37 -0500
commit519a28c4ef5b5a70d29377c9baed50b455459ebd (patch)
treed637caf13fa0dc9b167b9ec45715915202a92bf5
parenta78901127cd8af401146df47595442c4d8a696f2 (diff)
card view cleanup. moved 'pile' into shiftclick on Perspective dropdown. fixed tags sorting.
-rw-r--r--packages/components/src/components/Dropdown/Dropdown.tsx371
-rw-r--r--packages/components/src/components/ListBox/ListBox.tsx90
-rw-r--r--packages/components/src/components/ListItem/ListItem.tsx197
-rw-r--r--src/client/util/CurrentUserUtils.ts4
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx14
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx3
-rw-r--r--src/client/views/global/globalScripts.ts36
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx9
8 files changed, 313 insertions, 411 deletions
diff --git a/packages/components/src/components/Dropdown/Dropdown.tsx b/packages/components/src/components/Dropdown/Dropdown.tsx
index d9fec5e9d..0953f412c 100644
--- a/packages/components/src/components/Dropdown/Dropdown.tsx
+++ b/packages/components/src/components/Dropdown/Dropdown.tsx
@@ -1,31 +1,32 @@
-import React, { useEffect, useState } from 'react'
-import { FaCaretDown, FaCaretLeft, FaCaretRight, FaCaretUp } from 'react-icons/fa'
-import { Popup, PopupTrigger } from '..'
-import { Colors, IGlobalProps, Placement, Type, getFontSize, getHeight, isDark , getFormLabelSize } from '../../global'
-import { IconButton } from '../IconButton'
-import { ListBox } from '../ListBox'
-import { IListItemProps, ListItem } from '../ListItem'
-import './Dropdown.scss'
-import { Tooltip } from '@mui/material'
+import React, { useState } from 'react';
+import { FaCaretDown, FaCaretLeft, FaCaretRight, FaCaretUp } from 'react-icons/fa';
+import { Popup, PopupTrigger } from '..';
+import { Colors, IGlobalProps, Placement, Type, getFontSize, getHeight, isDark, getFormLabelSize } from '../../global';
+import { IconButton } from '../IconButton';
+import { ListBox } from '../ListBox';
+import { IListItemProps, ListItem } from '../ListItem';
+import './Dropdown.scss';
+import { Tooltip } from '@mui/material';
export enum DropdownType {
- SELECT = "select",
- CLICK = "click"
+ SELECT = 'select',
+ CLICK = 'click',
}
export interface IDropdownProps extends IGlobalProps {
- items: IListItemProps[]
- placement?: Placement
- dropdownType: DropdownType
- title?: string
- closeOnSelect?: boolean;
- iconProvider?: (active:boolean, placement?:Placement) => JSX.Element,
- selectedVal?: string,
- setSelectedVal?: (val: string | number) => unknown,
- maxItems?: number,
- uppercase?: boolean,
- activeChanged?: (isOpen:boolean) => void,
- onItemDown?: (e:React.PointerEvent, val:number | string) => boolean, // returns whether to select item
+ items: IListItemProps[];
+ placement?: Placement;
+ dropdownType: DropdownType;
+ title?: string;
+ toolTip?: string;
+ closeOnSelect?: boolean;
+ iconProvider?: (active: boolean, placement?: Placement) => JSX.Element;
+ selectedVal?: string;
+ setSelectedVal?: (val: string | number, e?: React.MouseEvent) => unknown;
+ maxItems?: number;
+ uppercase?: boolean;
+ activeChanged?: (isOpen: boolean) => void;
+ onItemDown?: (e: React.PointerEvent, val: number | string) => boolean; // returns whether to select item
}
/**
@@ -37,189 +38,159 @@ export interface IDropdownProps extends IGlobalProps {
* Look at: import Select from "react-select";
*/
export const Dropdown = (props: IDropdownProps) => {
- const {
- size,
- height,
- maxItems,
- items,
- dropdownType,
- selectedVal,
- setSelectedVal,
- iconProvider,
- placement = 'bottom-start',
- tooltip,
- tooltipPlacement = 'top',
- inactive,
- color = Colors.MEDIUM_BLUE,
- background,
- closeOnSelect,
- title = "Dropdown",
- type,
- width,
- formLabel,
- formLabelPlacement,
- fillWidth = true,
- onItemDown,
- uppercase
- } = props
+ const {
+ size,
+ height,
+ maxItems,
+ items,
+ dropdownType,
+ selectedVal,
+ toolTip,
+ setSelectedVal,
+ iconProvider,
+ placement = 'bottom-start',
+ tooltip,
+ tooltipPlacement = 'top',
+ inactive,
+ color = Colors.MEDIUM_BLUE,
+ background,
+ closeOnSelect,
+ title = 'Dropdown',
+ type,
+ width,
+ formLabel,
+ formLabelPlacement,
+ fillWidth = true,
+ onItemDown,
+ uppercase,
+ } = props;
- const [active, setActive] = useState<boolean>(false)
- const itemsMap = new Map();
- items.forEach((item) => {
- itemsMap.set(item.val, item)
- })
+ const [active, setActive] = useState<boolean>(false);
+ const itemsMap = new Map();
+ items.forEach(item => {
+ itemsMap.set(item.val, item);
+ });
- const getBorderColor = (): Colors | string | undefined => {
- switch(type){
- case Type.PRIM:
- return undefined;
- case Type.SEC:
- return color;
- case Type.TERT:
- if (active) return color;
- else return color;
- }
- }
+ const getBorderColor = (): Colors | string | undefined => {
+ switch (type) {
+ case Type.PRIM:
+ return undefined;
+ case Type.SEC:
+ return color;
+ case Type.TERT:
+ if (active) return color;
+ else return color;
+ }
+ };
- const defaultProperties: React.CSSProperties = {
- height: getHeight(height, size),
- width: fillWidth ? '100%' : width,
- fontWeight: 500,
- fontSize: getFontSize(size),
- fontFamily: 'sans-serif',
- textTransform: uppercase ? 'uppercase' : undefined,
- borderColor: getBorderColor(),
- background,
- color: color && background? color : type == (Type.TERT) ? isDark(color) ? Colors.WHITE : Colors.BLACK : color
- }
+ const defaultProperties: React.CSSProperties = {
+ height: getHeight(height, size),
+ width: fillWidth ? '100%' : width,
+ fontWeight: 500,
+ fontSize: getFontSize(size),
+ fontFamily: 'sans-serif',
+ textTransform: uppercase ? 'uppercase' : undefined,
+ borderColor: getBorderColor(),
+ background,
+ color: color && background ? color : type == Type.TERT ? (isDark(color) ? Colors.WHITE : Colors.BLACK) : color,
+ };
- const backgroundProperties: React.CSSProperties = {
- background: background ?? color
- }
+ const backgroundProperties: React.CSSProperties = {
+ background: background ?? color,
+ };
- const getCaretDirection = (active: boolean, placement:Placement = 'left'): JSX.Element => {
- if (iconProvider) return iconProvider(active, placement);
- switch (placement) {
- case 'bottom':
- if (active) return <FaCaretUp/>
- return <FaCaretDown/>
- case 'right':
- if (active) return <FaCaretLeft/>
- return <FaCaretRight/>
- case 'top':
- if (active) return <FaCaretDown/>
- return <FaCaretUp/>
- default:
- if (active) return <FaCaretUp/>
- return <FaCaretDown/>
- }
- }
+ const getCaretDirection = (active: boolean, placement: Placement = 'left'): JSX.Element => {
+ if (iconProvider) return iconProvider(active, placement);
+ switch (placement) {
+ case 'bottom':
+ if (active) return <FaCaretUp />;
+ return <FaCaretDown />;
+ case 'right':
+ if (active) return <FaCaretLeft />;
+ return <FaCaretRight />;
+ case 'top':
+ if (active) return <FaCaretDown />;
+ return <FaCaretUp />;
+ default:
+ if (active) return <FaCaretUp />;
+ return <FaCaretDown />;
+ }
+ };
- const getToggle = () => {
- switch (dropdownType) {
- case DropdownType.SELECT:
- return (
- <div
- className={`dropdown-toggle${!selectedVal?"-mini":""} ${type} ${inactive && 'inactive'}`}
- style={{...defaultProperties, height: getHeight(height, size), width: width }}
- >
- {selectedVal && (
- <ListItem
- size={size}
- {...itemsMap.get(selectedVal)}
- style={{ color: defaultProperties.color, background: defaultProperties.background}}
- inactive
- />
- )}
- <div className="toggle-caret">
- <IconButton
+ const getToggle = () => {
+ switch (dropdownType) {
+ case DropdownType.SELECT:
+ return (
+ <div className={`dropdown-toggle${!selectedVal ? '-mini' : ''} ${type} ${inactive && 'inactive'}`} style={{ ...defaultProperties, height: getHeight(height, size), width: width }}>
+ {selectedVal && <ListItem size={size} {...itemsMap.get(selectedVal)} style={{ color: defaultProperties.color, background: defaultProperties.background }} inactive />}
+ <div className="toggle-caret">
+ <IconButton size={size} icon={getCaretDirection(active, placement)} color={defaultProperties.color} inactive />
+ </div>
+ <div className={`background ${active && 'active'}`} style={{ ...backgroundProperties }} />
+ </div>
+ );
+ case DropdownType.CLICK:
+ default:
+ return (
+ <div className={`dropdown-toggle${!selectedVal ? '-mini' : ''} ${type} ${inactive && 'inactive'}`} style={{ ...defaultProperties, height: getHeight(height, size), width: width }}>
+ <ListItem val="title" text={title} size={size} style={{ color: defaultProperties.color, background: defaultProperties.backdropFilter }} inactive />
+ <div className="toggle-caret">
+ <IconButton size={size} icon={getCaretDirection(active, placement)} color={defaultProperties.color} inactive />
+ </div>
+ <div className={`background ${active && 'active'}`} style={{ ...backgroundProperties }} />
+ </div>
+ );
+ }
+ };
+
+ const setActiveChanged = (active: boolean) => {
+ setActive(active);
+ props.activeChanged?.(active);
+ };
+
+ const dropdown: JSX.Element = (
+ <div className="dropdown-container">
+ <Popup
+ toggle={
+ <Tooltip disableInteractive={true} arrow={true} placement={tooltipPlacement} title={toolTip || (itemsMap.get(selectedVal)?.text ?? title)}>
+ {getToggle()}
+ </Tooltip>
+ }
+ placement={placement}
+ tooltip={tooltip}
+ tooltipPlacement={tooltipPlacement}
+ trigger={PopupTrigger.CLICK}
+ isOpen={active}
+ setOpen={setActiveChanged}
size={size}
- icon={getCaretDirection(active,placement)}
- color={defaultProperties.color}
- inactive
- />
- </div>
- <div className={`background ${active && 'active'}`} style={{...backgroundProperties}}/>
- </div>
- )
- case DropdownType.CLICK:
- default:
- return (
- <div
- className={`dropdown-toggle${!selectedVal?"-mini":""} ${type} ${inactive && 'inactive'}`}
- style={{...defaultProperties, height: getHeight(height, size), width: width }}
- >
- <ListItem val='title'
- text={title}
- size={size}
- style={{ color: defaultProperties.color, background: defaultProperties.backdropFilter}}
- inactive
+ fillWidth={true}
+ color={color}
+ popup={
+ <ListBox
+ maxItems={maxItems}
+ items={items}
+ color={color}
+ onItemDown={onItemDown}
+ selectedVal={selectedVal}
+ setSelectedVal={(val, e) => {
+ setSelectedVal?.(val, e);
+ closeOnSelect && setActive(false);
+ }}
+ size={size}
+ />
+ }
/>
- <div className="toggle-caret">
- <IconButton
- size={size}
- icon={getCaretDirection(active,placement)}
- color={defaultProperties.color}
- inactive
- />
- </div>
- <div className={`background ${active && 'active'}`} style={{...backgroundProperties}}/>
- </div>
- )
- }
- }
-
- const setActiveChanged = (active:boolean) => {
- setActive(active);
- props.activeChanged?.(active);
- }
-
- const dropdown: JSX.Element =
- (
- <div
- className="dropdown-container"
- >
- <Popup
- toggle={
- <Tooltip disableInteractive={true} arrow={true} placement={tooltipPlacement} title={itemsMap.get(selectedVal) ? itemsMap.get(selectedVal).text : title}>
- {getToggle()}
- </Tooltip>
- }
- placement={placement}
- tooltip={tooltip}
- tooltipPlacement={tooltipPlacement}
- trigger={PopupTrigger.CLICK}
- isOpen={active}
- setOpen={setActiveChanged}
- size={size}
- fillWidth={true}
- color={color}
- popup={
- <ListBox
- maxItems={maxItems}
- items={items}
- color={color}
- onItemDown={onItemDown}
- selectedVal={selectedVal}
- setSelectedVal={val => {
- setSelectedVal?.(val);
- closeOnSelect && setActive(false);
- }}
- size={size}
- />
- }
- />
- </div>
- )
+ </div>
+ );
- return (
- formLabel ?
- <div className={`form-wrapper ${formLabelPlacement}`}
-style={{ width: fillWidth ? '100%' : undefined}}>
- <div className={'formLabel'} style={{fontSize: getFormLabelSize(size)}}>{formLabel}</div>
- {dropdown}
- </div>
- :
- dropdown
- )
-}
+ return formLabel ? (
+ <div className={`form-wrapper ${formLabelPlacement}`} style={{ width: fillWidth ? '100%' : undefined }}>
+ <div className={'formLabel'} style={{ fontSize: getFormLabelSize(size) }}>
+ {formLabel}
+ </div>
+ {dropdown}
+ </div>
+ ) : (
+ dropdown
+ );
+};
diff --git a/packages/components/src/components/ListBox/ListBox.tsx b/packages/components/src/components/ListBox/ListBox.tsx
index abdfd38f3..aa5eb6b44 100644
--- a/packages/components/src/components/ListBox/ListBox.tsx
+++ b/packages/components/src/components/ListBox/ListBox.tsx
@@ -1,15 +1,15 @@
-import React, { ReactText } from 'react'
-import { IListItemProps, ListItem } from '../ListItem'
-import './ListBox.scss'
-import { Colors, IGlobalProps, isDark , getFormLabelSize } from '../../global'
+import React from 'react';
+import { IListItemProps, ListItem } from '../ListItem';
+import './ListBox.scss';
+import { Colors, IGlobalProps } from '../../global';
export interface IListBoxProps extends IGlobalProps {
- items: IListItemProps[]
- filter?: string
- selectedVal?: string | number
- setSelectedVal?: (val: string | number) => unknown
- maxItems?: number
- onItemDown?: (e:React.PointerEvent, val:number|string) => void
+ items: IListItemProps[];
+ filter?: string;
+ selectedVal?: string | number;
+ setSelectedVal?: (val: string | number, e?: React.MouseEvent) => unknown;
+ maxItems?: number;
+ onItemDown?: (e: React.PointerEvent, val: number | string) => void;
}
/**
@@ -21,56 +21,24 @@ export interface IListBoxProps extends IGlobalProps {
* Look at: import Select from "react-select";
*/
export const ListBox = (props: IListBoxProps) => {
- const {
- items,
- selectedVal,
- setSelectedVal,
- filter,
- onItemDown,
- color = Colors.MEDIUM_BLUE
- } = props
+ const { items, selectedVal, setSelectedVal, filter, onItemDown, color = Colors.MEDIUM_BLUE } = props;
- const getListItem = (
- item: IListItemProps,
- ind: number,
- selected: boolean
- ): JSX.Element => {
+ const getListItem = (item: IListItemProps, ind: number, selected: boolean): JSX.Element => {
+ return <ListItem key={ind} ind={ind} onItemDown={onItemDown} selected={selected} color={color} setSelectedVal={setSelectedVal} onClick={item.onClick} {...item} />;
+ };
+ const itemElements: JSX.Element[] = [];
+ items.forEach((item, ind) => {
+ if (filter) {
+ if (filter.toLowerCase() === item.text?.substring(0, filter.length).toLowerCase()) {
+ itemElements.push(getListItem(item, ind, item.val === selectedVal));
+ }
+ } else {
+ itemElements.push(getListItem(item, ind, item.val === selectedVal));
+ }
+ });
return (
- <ListItem
- key={ind}
- ind={ind}
- onItemDown={onItemDown}
- selected={selected}
- color={color}
- setSelectedVal={setSelectedVal}
- onClick={item.onClick}
- {...item}
- />
- )
- }
- let itemElements: JSX.Element[] = []
- items.forEach((item, ind) => {
- if (filter) {
- if (
- filter.toLowerCase() ===
- item.text?.substring(0, filter.length).toLowerCase()
- ) {
- itemElements.push(
- getListItem(item, ind, item.val === selectedVal)
- )
- }
- } else {
- itemElements.push(
- getListItem(item, ind, item.val === selectedVal)
- )
- }
- })
- return (
- <div
- className="listBox-container"
- style={{ color: color }}
- >
- {itemElements}
- </div>
- )
-}
+ <div className="listBox-container" style={{ color: color }}>
+ {itemElements}
+ </div>
+ );
+};
diff --git a/packages/components/src/components/ListItem/ListItem.tsx b/packages/components/src/components/ListItem/ListItem.tsx
index d76c84b3e..e04c6fbee 100644
--- a/packages/components/src/components/ListItem/ListItem.tsx
+++ b/packages/components/src/components/ListItem/ListItem.tsx
@@ -1,25 +1,25 @@
-import React, { useState } from 'react'
-import * as fa from 'react-icons/fa'
-import { getFontSize, IGlobalProps, Type , getFormLabelSize, getHeight } from '../../global'
-import { Size } from '../../global/globalEnums'
-import { IconButton } from '../IconButton'
-import { ListBox } from '../ListBox'
-import { Popup, PopupTrigger } from '../Popup'
-import './ListItem.scss'
+import React, { useState } from 'react';
+import * as fa from 'react-icons/fa';
+import { getFontSize, IGlobalProps, Type, getHeight } from '../../global';
+import { Size } from '../../global/globalEnums';
+import { IconButton } from '../IconButton';
+import { ListBox } from '../ListBox';
+import { Popup, PopupTrigger } from '../Popup';
+import './ListItem.scss';
export interface IListItemProps extends IGlobalProps {
- ind?: number
- text?: string
- val: string | number
- icon?: JSX.Element
- description?: string
- shortcut?: string
- items?: IListItemProps[]
- selected?: boolean
- setSelectedVal?: (val: string | number) => unknown
- onClick?: () => void
- onItemDown?: (e:React.PointerEvent, val:string| number) => void
- uppercase?: boolean
+ ind?: number;
+ text?: string;
+ val: string | number;
+ icon?: JSX.Element;
+ description?: string;
+ shortcut?: string;
+ items?: IListItemProps[];
+ selected?: boolean;
+ setSelectedVal?: (val: string | number, e?: React.MouseEvent) => unknown;
+ onClick?: () => void;
+ onItemDown?: (e: React.PointerEvent, val: string | number) => void;
+ uppercase?: boolean;
}
/**
@@ -31,104 +31,67 @@ export interface IListItemProps extends IGlobalProps {
* Look at: import Select from "react-select";
*/
export const ListItem = (props: IListItemProps) => {
- const {
- ind,
- val,
- description,
- text,
- shortcut,
- items,
- icon,
- selected,
- setSelectedVal,
- onClick,
- onItemDown,
- inactive,
- size = Size.SMALL,
- style,
- color,
- background,
- uppercase
- } = props
+ const { val, description, text, shortcut, items, icon, selected, setSelectedVal, onClick, onItemDown, inactive, size = Size.SMALL, style, color, background, uppercase } = props;
- const [isHovered, setIsHovered] = useState<boolean>(false);
+ const [isHovered, setIsHovered] = useState<boolean>(false);
- let listItem:JSX.Element = (
- <div
- tabIndex={-1}
- className="listItem-container"
- onPointerDown={(e) => onItemDown?.(e, val) && setSelectedVal?.(val)}
- onClick={(e: React.MouseEvent) => {
- if (!items) {
- !inactive && onClick?.()
- !inactive && onClick && e.stopPropagation()
- setSelectedVal?.(val)
- }
- }}
- style={{
- minHeight: getHeight(undefined, size),
- userSelect: 'none',
- ...style
- }}
- onPointerEnter={() => {
- setIsHovered(true)
- }}
- onPointerLeave={() => {
- setIsHovered(false)
- }}
- >
- <div className="listItem-top">
- <div className="content"
- style={{
- fontSize: getFontSize(size),
- color: style?.color ? style.color : color
- }}>
- {icon}
- <div className="text" style={{
- textTransform: uppercase ? 'uppercase' : undefined
- }}>{text}</div>
+ const listItem: JSX.Element = (
+ <div
+ tabIndex={-1}
+ className="listItem-container"
+ onPointerDown={e => onItemDown?.(e, val) && setSelectedVal?.(val, e)}
+ onClick={(e: React.MouseEvent) => {
+ if (!items) {
+ !inactive && onClick?.();
+ !inactive && onClick && e.stopPropagation();
+ setSelectedVal?.(val, e);
+ }
+ }}
+ style={{
+ minHeight: getHeight(undefined, size),
+ userSelect: 'none',
+ ...style,
+ }}
+ onPointerEnter={() => {
+ setIsHovered(true);
+ }}
+ onPointerLeave={() => {
+ setIsHovered(false);
+ }}>
+ <div className="listItem-top">
+ <div
+ className="content"
+ style={{
+ fontSize: getFontSize(size),
+ color: style?.color ? style.color : color,
+ }}>
+ {icon}
+ <div
+ className="text"
+ style={{
+ textTransform: uppercase ? 'uppercase' : undefined,
+ }}>
+ {text}
+ </div>
+ </div>
+ {shortcut && !inactive && (
+ <div className="shortcut" color={style?.color ? style.color : color}>
+ {shortcut}
+ </div>
+ )}
+ {items && !inactive && <IconButton type={Type.PRIM} size={Size.SMALL} icon={<fa.FaCaretRight />} color={style?.color ? style.color : color} background={background} inactive />}
+ </div>
+ {description && !inactive && <div className="listItem-description">{description}</div>}
+ <div
+ className="listItem-background"
+ style={{
+ background: background ? background : style?.color ? style.color : color,
+ filter: selected ? 'opacity(0.3)' : isHovered && !inactive ? 'opacity(0.2)' : 'opacity(0)',
+ }}
+ />
</div>
- {shortcut && !inactive && (
- <div
- className="shortcut"
- color={style?.color ? style.color : color}
- >
- {shortcut}
- </div>
- )}
- {items && !inactive && (
- <IconButton
- type={Type.PRIM}
- size={Size.SMALL}
- icon={<fa.FaCaretRight/>}
- color={style?.color ? style.color : color}
- background={background}
- inactive
- />
- )}
- </div>
- {description && !inactive && (
- <div className="listItem-description">{description}</div>
- )}
- <div className="listItem-background"
- style={{
- background: background ? background : style?.color ? style.color : color,
- filter: selected ? 'opacity(0.3)' : isHovered && !inactive ? 'opacity(0.2)' : 'opacity(0)'
- }}
- />
- </div>
-)
+ );
- if (items && !inactive) return <Popup
- placement={'right'}
- toggle={listItem}
- color={color}
- background={background}
- trigger={PopupTrigger.CLICK}
- popup={
- <ListBox color={color} background={background} items={items}/>
- }
- fillWidth={true}
- />
- else return <>{listItem}</>
-}
+ if (items && !inactive) return <Popup placement={'right'} toggle={listItem} color={color} background={background} trigger={PopupTrigger.CLICK} popup={<ListBox color={color} background={background} items={items} />} fillWidth={true} />;
+ else return <>{listItem}</>;
+};
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b41fd09dc..7c36a82f2 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -694,10 +694,8 @@ pie title Minerals in my tap water
{ title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Tags", icon:"bolt", toolTip:"Sort by document's tags", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"tag", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "Pile", icon:"layer-group", toolTip:"View the cards as a pile in the free form view", btnType: ButtonType.ClickButton, expertMode: false, toolType:"pile", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Chat Popup",icon:"lightbulb", toolTip:"Toggle the chat popup's visibility", width: 45, btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
{ title: "Show Tags", icon:"id-card", toolTip:"Toggle tag annotation panel", width: 45, btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-tags",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
-
{ title: "Sort", icon: "sort" , toolTip: "Manage sort order / lock status", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true,
subMenu: [
{ title: "Ascending", toolTip: "Sort the cards in ascending order", btnType: ButtonType.ToggleButton, icon: "sort-up", toolType:"up", ignoreClick: true, scripts: {onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
@@ -814,7 +812,7 @@ pie title Minerals in my tap water
CollectionViewType.Masonry, CollectionViewType.Multicolumn, CollectionViewType.Multirow, CollectionViewType.Linear,
CollectionViewType.Map, CollectionViewType.NoteTaking, CollectionViewType.Schema, CollectionViewType.Stacking,
CollectionViewType.Calendar, CollectionViewType.Grid, CollectionViewType.Tree, CollectionViewType.Time, ]),
- title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setView(value, _readOnly_); }'}},
+ title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setView(value, shiftKey, _readOnly_); }'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}},
{ title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} },
{ title: "Template",icon: "scroll", toolTip: "Default Note Template",btnType: ButtonType.ToggleButton, expertMode: false, toolType:DocumentType.RTF, scripts: { onClick: '{ return setDefaultTemplate(_readOnly_); }'} },
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index d9ff21035..15683ebf2 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -16,6 +16,7 @@ import { RegionHelpers } from './Region';
import './Timeline.scss';
import { TimelineOverview } from './TimelineOverview';
import { Track } from './Track';
+import { Id } from '../../../fields/FieldSymbols';
/**
* Timeline class controls most of timeline functions besides individual region and track mechanism. Main functions are
@@ -56,7 +57,7 @@ export class Timeline extends ObservableReactComponent<FieldViewProps> {
private DEFAULT_CONTAINER_HEIGHT: number = 330;
private MIN_CONTAINER_HEIGHT: number = 205;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -89,7 +90,7 @@ export class Timeline extends ObservableReactComponent<FieldViewProps> {
*/
@computed
private get children(): Doc[] {
- const annotatedDoc = [DocumentType.IMG, DocumentType.VID, DocumentType.PDF, DocumentType.MAP].includes(StrCast(this._props.Document.type) as any);
+ const annotatedDoc = [DocumentType.IMG, DocumentType.VID, DocumentType.PDF, DocumentType.MAP].includes(StrCast(this._props.Document.type) as unknown as DocumentType);
if (annotatedDoc) {
return DocListCast(this._props.Document[Doc.LayoutFieldKey(this._props.Document) + '_annotations']);
}
@@ -272,9 +273,9 @@ export class Timeline extends ObservableReactComponent<FieldViewProps> {
* for displaying time to standard min:sec
*/
@action
- toReadTime = (time: number): string => {
- time = time / 1000;
- const inSeconds = Math.round(time * 100) / 100;
+ toReadTime = (timeIn: number): string => {
+ const timeSecs = timeIn / 1000;
+ const inSeconds = Math.round(timeSecs * 100) / 100;
const min = Math.floor(inSeconds / 60);
const sec = Math.round((inSeconds % 60) * 100) / 100;
@@ -552,6 +553,7 @@ export class Timeline extends ObservableReactComponent<FieldViewProps> {
<div key="timeline_trackbox" className="trackbox" ref={this._trackbox} style={{ width: `${this._totalLength}px` }}>
{[...this.children, this._props.Document].map(doc => (
<Track
+ key={doc[Id]}
ref={ref => this.mapOfTracks.push(ref)}
timeline={this}
animatedDoc={doc}
@@ -570,7 +572,7 @@ export class Timeline extends ObservableReactComponent<FieldViewProps> {
<div className="currentTime">Current: {this.getCurrentTime()}</div>
<div key="timeline_title" className="title-container" ref={this._titleContainer}>
{[...this.children, this._props.Document].map(doc => (
- <div style={{ height: `${this._titleHeight}px` }} className="datapane" onPointerOver={() => Doc.BrushDoc(doc)} onPointerOut={() => Doc.UnBrushDoc(doc)}>
+ <div key={doc[Id]} style={{ height: `${this._titleHeight}px` }} className="datapane" onPointerOver={() => Doc.BrushDoc(doc)} onPointerOut={() => Doc.UnBrushDoc(doc)}>
<p>{StrCast(doc.title)}</p>
</div>
))}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 800eb4914..1bca68846 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -5,7 +5,7 @@ import * as React from 'react';
import * as CSS from 'csstype';
import { ClientUtils, DashColor, imageUrlToBase64, returnFalse, returnNever, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { Animation, DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
@@ -314,6 +314,7 @@ export class CollectionCardView extends CollectionSubView() {
case cardSortings.Chat: return [NumCast(docA.chatIndex, 9999), NumCast(docB.chatIndex,9999)];
case cardSortings.Time: return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
case cardSortings.Color:return [DashColor(StrCast(docA.backgroundColor)).hsv().hue(), DashColor(StrCast(docB.backgroundColor)).hsv().hue()];
+ case cardSortings.Tag: return [StrListCast(docA.tags).join(""), StrListCast(docB.tags).join("")];
}
})(); //prettier-ignore
return (typeA < typeB ? -1 : typeA > typeB ? 1 : 0) * (isDesc ? 1 : -1);
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 1738802b7..542417531 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -48,10 +48,20 @@ ScriptingGlobals.add(function IsNoneSelected() {
// toggle: Set overlay status of selected document
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function setView(view: string, getSelected: boolean) {
- if (getSelected) return DocumentView.SelectedDocs();
- const selected = DocumentView.SelectedDocs().lastElement();
- selected ? (selected._type_collection = view) : console.log('[FontIconBox.tsx] changeView failed');
+ScriptingGlobals.add(function setView(view: string, shiftKey: boolean, checkResult?: boolean) {
+ if (checkResult) return DocumentView.SelectedDocs();
+ const selected = DocumentView.Selected().lastElement();
+ if (selected) {
+ if (shiftKey) {
+ const newCol = Doc.MakeEmbedding(selected.Document);
+ newCol._type_collection = view;
+ selected._props.addDocTab?.(newCol, OpenWhere.addRight);
+ } else {
+ selected.Document._type_collection = view;
+ }
+ } else {
+ console.log('[FontIconBox.tsx] changeView failed');
+ }
return undefined;
});
@@ -141,7 +151,7 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function showFreeform(
- attr: 'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'toggle-tags' | 'tag',
+ attr: 'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'toggle-chat' | 'toggle-tags' | 'tag',
checkResult?: boolean,
persist?: boolean
) {
@@ -152,7 +162,7 @@ ScriptingGlobals.add(function showFreeform(
}
// prettier-ignore
- const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'toggle-tags' | 'tag',
+ const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down'| 'toggle-chat' | 'toggle-tags' | 'tag',
{
waitForRender?: boolean;
checkResult: (doc: Doc) => boolean;
@@ -242,20 +252,6 @@ ScriptingGlobals.add(function showFreeform(
doc.showChildTags = !doc.showChildTags;
},
}],
- ['pile', {
- checkResult: (doc: Doc) => doc._type_collection == CollectionViewType.Freeform,
- setDoc: (doc: Doc, dv: DocumentView) => {
- const newCol = Docs.Create.CarouselDocument(DocListCast(doc[Doc.LayoutFieldKey(doc)]), {
- title: doc.title + "_carousel",
- _width: 250,
- _height: 200,
- _layout_fitWidth: false,
- _layout_autoHeight: true,
- childFilters: new List<string>(StrListCast(doc.childFilters))
- });
- dv._props.addDocTab?.(newCol, OpenWhere.addRight);
- },
- }],
]);
if (checkResult) {
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 60b2a7519..f58862028 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -160,6 +160,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
buttonList,
jsx: undefined,
selectedVal: script(),
+ toolTip: 'Set text font',
getStyle: (val: string) => ({ fontFamily: val }),
};
};
@@ -174,6 +175,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
buttonList: buttonList.filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value as CollectionViewType)),
getStyle: undefined,
selectedVal: StrCast(selected[0]._type_collection),
+ toolTip: 'change view type (press Shift to add as a new view)',
}
: {
jsx: selected.length ? (
@@ -205,11 +207,11 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
@computed get dropdownListButton() {
const script = ScriptCast(this.Document.script);
const selectedFunc = () => script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string;
- const { buttonList, selectedVal, getStyle, jsx } = (() => {
+ const { buttonList, selectedVal, getStyle, jsx, toolTip } = (() => {
switch (this.Document.title) {
case 'Font': return this.handleFontDropdown(selectedFunc, this.buttonList);
case 'Perspective': return this.handleViewDropdown(script, this.buttonList);
- default: return { buttonList: this.buttonList, selectedVal: selectedFunc(), jsx: undefined, getStyle: undefined };
+ default: return { buttonList: this.buttonList, selectedVal: selectedFunc(), toolTip: undefined, jsx: undefined, getStyle: undefined };
} // prettier-ignore
})();
if (jsx) return jsx;
@@ -225,9 +227,10 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
return (
<Dropdown
selectedVal={selectedVal}
- setSelectedVal={undoable(value => script.script.run({ this: this.Document, value }), `dropdown select ${this.label}`)}
+ setSelectedVal={undoable((value, e) => script.script.run({ this: this.Document, value, shiftKey: e.shiftKey }), `dropdown select ${this.label}`)}
color={SnappingManager.userColor}
background={SnappingManager.userVariantColor}
+ toolTip={toolTip}
type={Type.TERT}
closeOnSelect={false}
dropdownType={DropdownType.SELECT}