From f5c2f5bc8710a965a0b52e2e414f62a2a459a94f Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Sun, 25 Aug 2024 04:26:12 -0400 Subject: border work --- src/client/documents/Documents.ts | 2 + src/client/views/ContextMenu.scss | 35 ++++++++++ src/client/views/ContextMenu.tsx | 118 ++++++++++++++++++++++---------- src/client/views/ContextMenuItem.tsx | 12 +++- src/client/views/MainView.tsx | 6 +- src/client/views/PropertiesView.tsx | 10 +++ src/client/views/StyleProvider.tsx | 37 ++++++---- src/client/views/nodes/DocumentView.tsx | 37 ++++++---- 8 files changed, 191 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 751fe6d91..aecc79189 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -256,6 +256,8 @@ export class DocumentOptions { layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); layout_borderRounding?: string; _layout_borderRounding?: STRt = new StrInfo('amount of rounding to document view corners'); + _layout_borderWidth?: NUMt = new NumInfo('Hey now', false); + _layout_borderColor?: STRt = new StrInfo('No no', false); _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false); _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); _layout_reflowVertical?: BOOLt = new BoolInfo('permit vertical resizing with content "reflow"'); diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 232362c5c..ff6ad526e 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -165,3 +165,38 @@ border: solid black 1px; border-radius: 5px; } + +.contextMenu-borderMenu { + display: flex; + flex-direction: column; + align-items: flex-start; + width: 222px; + height: 300px; + background-color: white; + border: solid 1px black; + + .top-bar { + height: 20px; + width: 100%; + display: flex; + + .close-menu { + margin-top: 0; + margin-bottom: 0; + margin-right: 0; + padding: 0; + margin-left: auto; + z-index: 999999999; + width: 20px; + height: 20px; + color: black; + background-color: transparent; + } + } + + .bottom-box{ + .width-selector{ + + } + } +} diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index de985263d..9472fb95c 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -5,11 +5,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { DivHeight, DivWidth } from '../../ClientUtils'; +import { DivHeight, DivWidth, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { SnappingManager } from '../util/SnappingManager'; import './ContextMenu.scss'; import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { ColorResult, SketchPicker } from 'react-color'; +import { DocumentView } from './nodes/DocumentView'; +import { Doc } from '../../fields/Doc'; +import { undoable } from '../util/UndoManager'; +import { NumCast, StrCast } from '../../fields/Types'; +import { emptyFunction } from '../../Utils'; @observer export class ContextMenu extends ObservableReactComponent<{}> { @@ -38,6 +44,8 @@ export class ContextMenu extends ObservableReactComponent<{}> { @observable _mouseX: number = -1; @observable _mouseY: number = -1; @observable _shouldDisplay: boolean = false; + @observable _displayColorPicker: boolean = false; + @observable _selectorWidth: number = 0; constructor(props: any) { super(props); @@ -116,6 +124,10 @@ export class ContextMenu extends ObservableReactComponent<{}> { this._defaultItem = item; } + @action setColorPickerDisplay = (display: boolean) => { + this._displayColorPicker = display; + } + static readonly buffer = 20; get pageX() { return this._pageX + this._width > window.innerWidth - ContextMenu.buffer ? window.innerWidth - ContextMenu.buffer - this._width : Math.max(0, this._pageX); @@ -206,45 +218,79 @@ export class ContextMenu extends ObservableReactComponent<{}> { _searchRef = React.createRef(); // bcz: we shouldn't need this, since we set autoFocus on the tag, but for some reason we do... + get colorPicker() { + const doc = DocumentView.Selected().lastElement().Document; + const layoutDoc = doc ? Doc.Layout(doc) : doc; + + return ( +
+
+ +
+ layoutDoc._layout_borderColor = col.hex), + 'set stroke color property' + )} + presetColors={[]} + color={StrCast(layoutDoc._layout_borderColor)} + /> +
+ {layoutDoc._layout_borderWidth = e.target.value; this._selectorWidth = Number(e.target.value); console.log(layoutDoc._layout_borderWidth)}}/> +
+
+ ); + } + render() { this.itemsNeedSearch && setTimeout(() => this._searchRef.current?.focus()); return ( -
{ - if (r) { - this._width = DivWidth(r); - this._height = DivHeight(r); - } - this._searchRef.current?.focus(); - })} - style={{ - display: this._display ? '' : 'none', - left: this.pageX, - ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }), - background: SnappingManager.userBackgroundColor, - color: SnappingManager.userColor, - }}> - {!this.itemsNeedSearch ? null : ( - - - +
+ {this._displayColorPicker ? this.colorPicker : null} +
{ + if (r) { + this._width = DivWidth(r); + this._height = DivHeight(r); + } + this._searchRef.current?.focus(); + })} + style={{ + display: this._display ? '' : 'none', + left: this.pageX, + ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }), + background: SnappingManager.userBackgroundColor, + color: SnappingManager.userColor, + }}> + {!this.itemsNeedSearch ? null : ( + + + + + - - - )} - {this.menuItems} + )} + {this.menuItems} +
); } diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index eb1030eec..782077fd6 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -5,8 +5,14 @@ import { action, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { SnappingManager } from '../util/SnappingManager'; -import { UndoManager } from '../util/UndoManager'; +import { UndoManager, undoable } from '../util/UndoManager'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { ColorPicker, Type } from 'browndash-components'; +import { DocumentView } from './nodes/DocumentView'; +import { Doc } from '../../fields/Doc'; +import { StrCast } from '../../fields/Types'; +import { ColorResult, SketchPicker } from 'react-color'; +import color from 'color'; export interface OriginalMenuProps { description: string; @@ -14,6 +20,7 @@ export interface OriginalMenuProps { undoable?: boolean; icon: IconProp | JSX.Element; // maybe should be optional (icon?) closeMenu?: () => void; + colorPicker?: boolean; } export interface SubmenuProps { @@ -24,6 +31,7 @@ export interface SubmenuProps { addDivider?: boolean; icon: IconProp; // maybe should be optional (icon?) closeMenu?: () => void; + colorPicker?: boolean; } export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @@ -101,7 +109,7 @@ export class ContextMenuItem extends ObservableReactComponent +
{this._props.icon ? {this.isJSXElement(this._props.icon) ? this._props.icon : } : null}
{this._props.description.replace(':', '')}
{ public static Live: boolean = false; private _docBtnRef = React.createRef(); + @observable private _keepContextMenuOpen: boolean = false; @observable private _windowWidth: number = 0; @observable private _windowHeight: number = 0; @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) @@ -590,7 +591,10 @@ export class MainView extends ObservableReactComponent<{}> { if (typeof targets[i].className === 'object') targClass = targets[i + 1].className.toString(); else break; } - !targClass.includes('contextMenu') && ContextMenu.Instance.closeMenu(); + if (!targClass.includes('contextMenu')) { + console.log(targClass) + ContextMenu.Instance.closeMenu(); + } !['timeline-menu-desc', 'timeline-menu-item', 'timeline-menu-input'].includes(targClass) && TimelineMenu.Instance.closeMenu(); } }); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 024db82a4..775e15772 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -847,6 +847,12 @@ export class PropertiesView extends ObservableReactComponent void) { return ( @@ -898,6 +904,10 @@ export class PropertiesView extends ObservableReactComponent { this.colorStk = color; }); // prettier-ignore } + @computed get borderColorPicker() { + return this.colorPicker(this.colorStk, (color: string) => { this.colorStk = color; }); // prettier-ignore + } + @computed get strokeAndFill() { return (
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 8c100f238..3a48ec957 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -55,14 +55,25 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu return style; } -export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { - return `M ${pw * 0.5} ${ph * inset} C ${pw * 0.6} ${ph * inset} ${pw * (1 - 2 * inset)} 0 ${pw * (1 - inset)} ${ph * inset} C ${pw} ${ph * (2 * inset)} ${pw * (1 - inset)} ${ph * 0.25} ${pw * (1 - inset)} ${ph * 0.3} C ${ - pw * (1 - inset) - } ${ph * 0.4} ${pw} ${ph * (1 - 2 * inset)} ${pw * (1 - inset)} ${ph * (1 - inset)} C ${pw * (1 - 2 * inset)} ${ph} ${pw * 0.6} ${ph * (1 - inset)} ${pw * 0.5} ${ph * (1 - inset)} C ${pw * 0.3} ${ph * (1 - inset)} ${pw * (2 * inset)} ${ph} ${ - pw * inset - } ${ph * (1 - inset)} C 0 ${ph * (1 - 2 * inset)} ${pw * inset} ${ph * 0.8} ${pw * inset} ${ph * 0.75} C ${pw * inset} ${ph * 0.7} 0 ${ph * (2 * inset)} ${pw * inset} ${ph * inset} C ${pw * (2 * inset)} 0 ${pw * 0.25} ${ph * inset} ${ - pw * 0.5 - } ${ph * inset}`; +export function wavyBorderPath(doc: Doc, pw: number, ph: number, inset: number = 0) { + const layoutDoc = doc ? Doc.Layout(doc) : doc; + const width = pw * inset; + const height = ph * inset; + + const radius = Math.min(Number(StrCast(layoutDoc._layout_borderRounding).replace('px', '')), (pw - 2 * width) / 2, (ph - 2 * height) / 2); + + return ` + M ${width + radius} ${height} + L ${pw - width - radius} ${height} + A ${radius} ${radius} 0 0 1 ${pw - width} ${height + radius} + L ${pw - width} ${ph - height - radius} + A ${radius} ${radius} 0 0 1 ${pw - width - radius} ${ph - height} + L ${width + radius} ${ph - height} + A ${radius} ${radius} 0 0 1 ${width} ${ph - height - radius} + L ${width} ${height + radius} + A ${radius} ${radius} 0 0 1 ${width + radius} ${height} + Z + `; } let _filterOpener: () => void; @@ -189,10 +200,12 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt - +
), diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8edb37acc..fe6d529ba 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -634,6 +634,7 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => { this.Document._chromeHidden = !this.Document._chromeHidden; }, icon: 'project-diagram' }); // prettier-ignore moreItems.push({ description: 'Copy ID', event: () => ClientUtils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' }); + moreItems.push({ description: 'Add border', event: () => ContextMenu.Instance.setColorPickerDisplay(true), icon: 'square', colorPicker: true }); } } @@ -944,22 +945,28 @@ export class DocumentViewInternal extends DocComponent + //
+ //
+ //
+ //
(!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} - onPointerOver={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} - onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} - style={{ - borderRadius: this.borderRounding, - pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) - }}> - {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} - {borderPath?.jsx} -
+ className={`${DocumentView.ROOT_DIV} docView-hack`} + ref={this._mainCont} + onContextMenu={this.onContextMenu} + onPointerDown={this.onPointerDown} + onClick={SnappingManager.ExploreMode ? this.onBrowseClick : this.onClick} + onPointerEnter={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} + onPointerOver={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} + onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} + style={{ + borderRadius: this.borderRounding, + pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) + }}> + {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} + {borderPath?.jsx} +
+ //
); } -- cgit v1.2.3-70-g09d2