From 54308259a8cd3ac98aaee550ea01ad97f17172e6 Mon Sep 17 00:00:00 2001 From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com> Date: Mon, 17 Jul 2023 23:11:35 -0400 Subject: so many updates --- .../views/nodes/FontIconBox/ButtonInterface.ts | 12 + .../views/nodes/FontIconBox/FontIconBadge.scss | 11 + .../views/nodes/FontIconBox/FontIconBadge.tsx | 37 ++ .../views/nodes/FontIconBox/FontIconBox.scss | 438 +++++++++++++++++++++ src/client/views/nodes/FontIconBox/FontIconBox.tsx | 412 +++++++++++++++++++ 5 files changed, 910 insertions(+) create mode 100644 src/client/views/nodes/FontIconBox/ButtonInterface.ts create mode 100644 src/client/views/nodes/FontIconBox/FontIconBadge.scss create mode 100644 src/client/views/nodes/FontIconBox/FontIconBadge.tsx create mode 100644 src/client/views/nodes/FontIconBox/FontIconBox.scss create mode 100644 src/client/views/nodes/FontIconBox/FontIconBox.tsx (limited to 'src/client/views/nodes/FontIconBox') diff --git a/src/client/views/nodes/FontIconBox/ButtonInterface.ts b/src/client/views/nodes/FontIconBox/ButtonInterface.ts new file mode 100644 index 000000000..0aa2ac8e1 --- /dev/null +++ b/src/client/views/nodes/FontIconBox/ButtonInterface.ts @@ -0,0 +1,12 @@ +import { Doc } from "../../../../fields/Doc"; +import { IconProp } from "@fortawesome/fontawesome-svg-core"; +import { ButtonType } from "./FontIconBox"; + +export interface IButtonProps { + type: string | ButtonType; + rootDoc: Doc; + label: any; + icon: IconProp; + color: string; + backgroundColor: string; +} \ No newline at end of file diff --git a/src/client/views/nodes/FontIconBox/FontIconBadge.scss b/src/client/views/nodes/FontIconBox/FontIconBadge.scss new file mode 100644 index 000000000..78f506e57 --- /dev/null +++ b/src/client/views/nodes/FontIconBox/FontIconBadge.scss @@ -0,0 +1,11 @@ +.fontIconBadge { + background: red; + width: 15px; + height: 15px; + top: 8px; + display: block; + position: absolute; + right: 5; + border-radius: 50%; + text-align: center; +} \ No newline at end of file diff --git a/src/client/views/nodes/FontIconBox/FontIconBadge.tsx b/src/client/views/nodes/FontIconBox/FontIconBadge.tsx new file mode 100644 index 000000000..b50588ce2 --- /dev/null +++ b/src/client/views/nodes/FontIconBox/FontIconBadge.tsx @@ -0,0 +1,37 @@ +import { observer } from 'mobx-react'; +import * as React from 'react'; +import './FontIconBadge.scss'; + +interface FontIconBadgeProps { + value: string | undefined; +} + +@observer +export class FontIconBadge extends React.Component { + _notifsRef = React.createRef(); + + // onPointerDown = (e: React.PointerEvent) => { + // setupMoveUpEvents(this, e, + // (e: PointerEvent) => { + // const dragData = new DragManager.DocumentDragData([this.props.collection!]); + // DragManager.StartDocumentDrag([this._notifsRef.current!], dragData, e.x, e.y); + // return true; + // }, + // returnFalse, emptyFunction, false); + // } + + render() { + if (this.props.value === undefined) return null; + return ( +
+
+ {this.props.value} +
+
+ ); + } +} diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.scss b/src/client/views/nodes/FontIconBox/FontIconBox.scss new file mode 100644 index 000000000..9d9fa26b0 --- /dev/null +++ b/src/client/views/nodes/FontIconBox/FontIconBox.scss @@ -0,0 +1,438 @@ +@import '../../global/globalCssVariables'; + +.menuButton { + height: 100%; + display: flex; + justify-content: center; + align-items: center; + font-size: 80%; + border-radius: $standard-border-radius; + transition: 0.15s; + + .menuButton-wrap { + grid-column: 1; + justify-content: center; + align-items: center; + text-align: center; + } + + .fontIconBox-label { + color: $white; + bottom: -1; + position: absolute; + text-align: center; + font-size: 7px; + letter-spacing: normal; + background-color: inherit; + border-radius: 8px; + padding: 0; + width: 100%; + font-family: 'system-ui'; + text-transform: uppercase; + font-weight: bold; + transition: 0.15s; + } + + .fontIconBox-icon { + width: 80%; + height: 80%; + } + + &.clickBtn, + &.clickBtnLabel { + cursor: pointer; + flex-direction: column; + + svg { + width: 50% !important; + height: 50%; + } + } + + &.clickBtnLabel { + svg { + margin-top: -4px; + } + } + + &.textBtn { + display: grid; + /* grid-row: auto; */ + grid-auto-flow: column; + cursor: pointer; + width: 100%; + justify-content: center; + align-items: center; + justify-items: center; + } + + &.tglBtn, + &.tglBtnLabel { + cursor: pointer; + flex-direction: column; + + &.switch { + //TOGGLE + + .switch { + position: relative; + display: inline-block; + width: 100%; + height: 25px; + margin: 0; + } + + .switch input { + opacity: 0; + width: 0; + height: 0; + } + + .slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: lightgrey; + -webkit-transition: 0.4s; + transition: 0.4s; + } + + .slider:before { + position: absolute; + content: ''; + height: 21px; + width: 21px; + left: 2px; + bottom: 2px; + background-color: $white; + -webkit-transition: 0.4s; + transition: 0.4s; + } + + input:checked + .slider { + background-color: $medium-blue; + } + + input:focus + .slider { + box-shadow: 0 0 1px $medium-blue; + } + + input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); + } + + /* Rounded sliders */ + .slider.round { + border-radius: $standard-border-radius; + } + + .slider.round:before { + border-radius: $standard-border-radius; + } + } + + svg { + width: 50% !important; + height: 50%; + } + + &:hover { + background-color: rgba(0, 0, 0, 0.3); + } + } + + &.tglBtnLabel { + svg { + margin-top: -4px; + } + } + + &.toolBtn, + &.toolBtnLabel { + cursor: pointer; + width: 100%; + border-radius: 100%; + flex-direction: column; + // margin-top: -4px; + + svg { + width: 60% !important; + height: 60%; + } + } + + &.toolBtnLabel { + svg { + margin-top: -4px; + } + } + + &.menuBtn { + cursor: pointer !important; + border-radius: 0px; + flex-direction: column; + + svg { + width: 45% !important; + height: 45%; + } + + &:hover { + filter: brightness(0.85); + } + } + + &.colorBtn, + &.colorBtnLabel { + color: black; + cursor: pointer; + flex-direction: column; + background: transparent; + + .colorButton-color { + margin-top: 3px; + width: 80%; + height: 3px; + } + + .menuButton-dropdownBox { + position: absolute; + width: fit-content; + height: fit-content; + color: black; + top: 100%; + left: 0; + z-index: 21; + background-color: #e3e3e3; + box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); + border-radius: 3px; + } + } + + &.colorBtnLabel { + svg { + margin-top: -4px; + } + } + + &.drpdownList { + width: 100%; + display: grid; + grid-auto-columns: 80px 20px; + justify-items: center; + font-family: 'Roboto'; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 13; + font-weight: 600; + overflow: hidden; + cursor: pointer; + background: transparent; + align-content: center; + align-items: center; + + .menuButton-dropdownList { + position: absolute; + width: 150px; + height: fit-content; + top: 100%; + z-index: 21; + background-color: $white; + box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); + padding: 1px; + + .list-item { + color: $black; + width: 100%; + height: 25px; + font-weight: 400; + display: flex; + justify-content: left; + align-items: center; + padding-left: 5px; + } + + .list-item:hover { + background-color: lightgrey; + } + } + } + + &.numBtn { + cursor: pointer; + background: transparent; + + &.slider { + color: $white; + cursor: pointer; + flex-direction: column; + background: transparent; + + .menu-slider { + width: 100px; + } + + .menuButton-dropdownBox { + position: absolute; + width: fit-content; + height: fit-content; + top: 100%; + z-index: 21; + background-color: #e3e3e3; + box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); + border-radius: $standard-border-radius; + + .menu-slider { + height: 10px; + } + input[type='range']::-webkit-slider-runnable-track { + background: gray; + height: 3px; + } + + input[type='range']::-webkit-slider-thumb { + box-shadow: 1px 1px 1px #000000; + border: 1px solid #000000; + height: 10px; + width: 10px; + border-radius: 5px; + background: #ffffff; + cursor: pointer; + -webkit-appearance: none; + margin-top: -4px; + } + } + } + + .button { + width: 25%; + display: flex; + align-items: center; + justify-content: center; + + &.number { + width: 50%; + + .button-input { + background: none; + border: none; + text-align: right; + width: 100%; + color: $white; + height: 100%; + text-align: center; + } + + .button-input:focus { + outline: none; + } + } + } + + &.list { + width: 100%; + justify-content: space-around; + border: $standard-border; + + .menuButton-dropdownList { + position: absolute; + width: fit-content; + height: fit-content; + min-width: 50%; + max-height: 50vh; + overflow-y: scroll; + top: 100%; + z-index: 21; + background-color: $white; + box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); + padding: 1px; + + .list-item { + color: $black; + width: 100%; + height: 25px; + font-weight: 400; + display: flex; + justify-content: center; + align-items: center; + } + + .list-item:hover { + background-color: lightgrey; + } + } + } + } + + &.editableText { + cursor: text; + display: flex; + flex-direction: row; + gap: 5px; + padding-left: 10px; + justify-content: flex-start; + color: black; + background-color: $light-gray; + padding: 5px; + padding-left: 10px; + width: 100%; + height: 100%; + } + + &.drpDownBtn { + cursor: pointer; + background: transparent; + border: solid 0.5px grey; + + &.true { + background: rgba(0, 0, 0, 0.3); + } + + .menuButton-dropdownBox { + position: absolute; + width: 150px; + height: 250px; + top: 100%; + background-color: #e3e3e3; + box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); + border-radius: $standard-border-radius; + } + } + + .menuButton-dropdown { + display: flex; + justify-content: center; + align-items: center; + font-size: 15px; + grid-column: 2; + border-radius: 0px 7px 7px 0px; + width: 13px; + height: 100%; + right: 0; + } + + .menuButton-dropdown-header { + width: 100%; + font-weight: 300; + padding: 5px; + overflow: hidden; + font-size: 12px; + white-space: nowrap; + text-overflow: ellipsis; + } + + .dropbox-background { + width: 200vw; + height: 200vh; + top: -100vh; + z-index: 20; + left: -100vw; + background: transparent; + position: fixed; + } +} diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx new file mode 100644 index 000000000..2958fa737 --- /dev/null +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -0,0 +1,412 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, NumberDropdown, NumberDropdownType, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; +import { ScriptField } from '../../../../fields/ScriptField'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; +import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; +import { SelectionManager } from '../../../util/SelectionManager'; +import { undoable, UndoManager } from '../../../util/UndoManager'; +import { ContextMenu } from '../../ContextMenu'; +import { DocComponent } from '../../DocComponent'; +import { EditableView } from '../../EditableView'; +import { Colors } from '../../global/globalEnums'; +import { StyleProp } from '../../StyleProvider'; +import { FieldView, FieldViewProps } from '../FieldView'; +import { OpenWhere } from '../DocumentView'; +import { RichTextMenu } from '../formattedText/RichTextMenu'; +import './FontIconBox.scss'; +import { SelectedDocView } from '../../selectedDoc'; + +export enum ButtonType { + TextButton = 'textBtn', + MenuButton = 'menuBtn', + DropdownList = 'dropdownList', + DropdownButton = 'dropdownBtn', + ClickButton = 'clickBtn', + ToggleButton = 'toggleBtn', + ColorButton = 'colorBtn', + ToolButton = 'toolBtn', + MultiToggleButton = 'multiToggleBtn', + NumberSliderButton = 'numSliderBtn', + NumberDropdownButton = 'numDropdownBtn', + NumberInlineButton = 'numInlineBtn', + EditableText = 'editableText', +} + +export interface ButtonProps extends FieldViewProps { + type?: ButtonType; +} +@observer +export class FontIconBox extends DocComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(FontIconBox, fieldKey); + } + @observable noTooltip = false; + showTemplate = (): void => { + const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null); + dragFactory && this.props.addDocTab(dragFactory, OpenWhere.addRight); + }; + dragAsTemplate = (): void => { + this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); + }; + useAsPrototype = (): void => { + this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); + }; + + specificContextMenu = (): void => { + if (!Doc.noviceMode) { + const cm = ContextMenu.Instance; + cm.addItem({ description: 'Show Template', event: this.showTemplate, icon: 'tag' }); + cm.addItem({ description: 'Use as Render Template', event: this.dragAsTemplate, icon: 'tag' }); + cm.addItem({ description: 'Use as Prototype', event: this.useAsPrototype, icon: 'tag' }); + } + }; + + static GetShowLabels() { + return BoolCast(Doc.UserDoc()._showLabel); + } + static SetShowLabels(show: boolean) { + Doc.UserDoc()._showLabel = show; + } + static GetRecognizeGestures() { + return BoolCast(Doc.UserDoc()._recognizeGestures); + } + static SetRecognizeGestures(show: boolean) { + Doc.UserDoc()._recognizeGestures = show; + } + + // Determining UI Specs + @computed get label() { + return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title)); + } + Icon = (color: string, iconFalse?: boolean) => { + let icon; + if (iconFalse ) { + icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any; + if (icon) return + else return null + } + icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any; + const trailsIcon = () => ; + return !icon ? null : icon === 'pres-trail' ? trailsIcon() : ; + }; + @computed get dropdown() { + return BoolCast(this.rootDoc.dropDownOpen); + } + @computed get buttonList() { + return StrListCast(this.rootDoc.btnList); + } + @computed get type() { + return StrCast(this.rootDoc.btnType); + } + + /** + * Types of buttons in dash: + * - Main menu button (LHS) + * - Tool button + * - Expandable button (CollectionLinearView) + * - Button inside of CollectionLinearView vs. outside of CollectionLinearView + * - Action button + * - Dropdown button + * - Color button + * - Dropdown list + * - Number button + **/ + + _batch: UndoManager.Batch | undefined = undefined; + /** + * Number button + */ + @computed get numberDropdown() { + let type: NumberDropdownType; + switch(this.type) { + case ButtonType.NumberDropdownButton: + type = 'dropdown' + break; + case ButtonType.NumberInlineButton: + type = 'input' + break; + case ButtonType.NumberSliderButton: + default: + type = 'slider' + break; + } + const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined }); + const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + // Script for checking the outcome of the toggle + const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3))); + const label = !FontIconBox.GetShowLabels() ? null :
{this.label}
; + + return numScript(value), `${this.rootDoc.title} button set from list`)} + fillWidth + /> + } + + /** + * Dropdown button + */ + @computed get dropdownButton() { + const active: string = StrCast(this.rootDoc.dropDownOpen); + const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + return ( +
{ + this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; + this.noTooltip = this.rootDoc.dropDownOpen; + Doc.UnBrushAllDocs(); + })}> + {this.Icon(color)} + {!this.label || !FontIconBox.GetShowLabels() ? null : ( +
+ {' '} + {this.label}{' '} +
+ )} +
+ +
+ {this.rootDoc.dropDownOpen ?
{/* DROPDOWN BOX CONTENTS */}
: null} +
+ ); + } + + /** + * Dropdown list + */ + @computed get dropdownListButton() { + const active: string = StrCast(this.rootDoc.dropDownOpen); + const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + + const script = ScriptCast(this.rootDoc.script); + + let noviceList: string[] = []; + let text: string | undefined; + let dropdown = true; + let getStyle: (val: string) => any = () => {}; + let icon: IconProp = 'caret-down'; + let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView') + try { + if (isViewDropdown) { + const selectedDocs: Doc[] = SelectionManager.Docs(); + const selected = SelectionManager.Docs().lastElement(); + console.log('selected') + if (selected) { + if (StrCast(selected.type) === DocumentType.COL) { + text = StrCast(selected._type_collection); + } else { + console.log("doc selected", selected.title); + dropdown = false; + if (selectedDocs.length > 1) { + text = selectedDocs.length + " documents selected" + } else { + text = selected.type === DocumentType.RTF ? 'Text' : StrCast(selected.type); + icon = Doc.toIcon(selected); + } + return } + text={text} + type={Type.TERT} + color={color} + popup={} + fillWidth + /> + } + } else { + dropdown = false; + return - - Pin to Presentation}> - - - Show Linked Trail}> - - - make target visibility toggle on click}> - - + {this.Delete !== returnFalse && } + color={StrCast(Doc.UserDoc().userColor)} + />} + {this.PinToPres !== returnFalse && } + color={StrCast(Doc.UserDoc().userColor)} + />} + {this.ShowTargetTrail !== returnFalse && } + color={StrCast(Doc.UserDoc().userColor)} + />} + {this.IsTargetToggler !== returnFalse && } + color={StrCast(Doc.UserDoc().userColor)} + />} ); diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 1c9e124a2..955a4a174 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -40,7 +40,7 @@ export class SelectedDocView extends React.Component { onClick: () => {DocumentManager.Instance.showDocument(doc, options, finished);} } })} - color={Colors.WHITE} + color={StrCast(Doc.UserDoc().userColor)} /> } diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index b9d5ed924..5c5547180 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -119,14 +119,6 @@ export class TopBar extends React.Component { dashView?.showContextMenu(e.clientX + 20, e.clientY + 30); }} /> -