aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-08-25 04:26:12 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-08-25 04:26:12 -0400
commitf5c2f5bc8710a965a0b52e2e414f62a2a459a94f (patch)
tree558c2125c3bd4e3cfb004552691cd482b98bfab0 /src
parent35724d24821132ab5c6df398447db4e9760155cb (diff)
border work
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/views/ContextMenu.scss35
-rw-r--r--src/client/views/ContextMenu.tsx118
-rw-r--r--src/client/views/ContextMenuItem.tsx12
-rw-r--r--src/client/views/MainView.tsx6
-rw-r--r--src/client/views/PropertiesView.tsx10
-rw-r--r--src/client/views/StyleProvider.tsx37
-rw-r--r--src/client/views/nodes/DocumentView.tsx37
8 files changed, 191 insertions, 66 deletions
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<HTMLInputElement>(); // bcz: we shouldn't need this, since we set autoFocus on the <input> tag, but for some reason we do...
+ get colorPicker() {
+ const doc = DocumentView.Selected().lastElement().Document;
+ const layoutDoc = doc ? Doc.Layout(doc) : doc;
+
+ return (
+ <div className='contextMenu-borderMenu' style={{position: 'absolute', right: `${this._pageX}`, top: `${this._pageY}`}}>
+ <div className='top-bar'>
+ <button className='close-menu' onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction,
+ undoable(clickEv => {
+ clickEv.stopPropagation();
+ clickEv.preventDefault();
+ this.setColorPickerDisplay(false);
+ }, 'close border menu'))}>
+ <FontAwesomeIcon icon='minus'/>
+ </button>
+ </div>
+ <SketchPicker
+ onChange={undoable(
+ action((col: ColorResult) => layoutDoc._layout_borderColor = col.hex),
+ 'set stroke color property'
+ )}
+ presetColors={[]}
+ color={StrCast(layoutDoc._layout_borderColor)}
+ />
+ <div className='bottom-box'>
+ <input className='width-selector' type="range" min="1" max="100" value={this._selectorWidth} id="myRange" onChange={e => {layoutDoc._layout_borderWidth = e.target.value; this._selectorWidth = Number(e.target.value); console.log(layoutDoc._layout_borderWidth)}}/>
+ </div>
+ </div>
+ );
+ }
+
render() {
this.itemsNeedSearch && setTimeout(() => this._searchRef.current?.focus());
return (
- <div
- className="contextMenu-cont"
- ref={action((r: any) => {
- 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 : (
- <span className="search-icon">
- <span className="icon-background">
- <FontAwesomeIcon icon="search" size="lg" />
+ <div>
+ {this._displayColorPicker ? this.colorPicker : null}
+ <div
+ className="contextMenu-cont"
+ ref={action((r: any) => {
+ 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 : (
+ <span className="search-icon">
+ <span className="icon-background">
+ <FontAwesomeIcon icon="search" size="lg" />
+ </span>
+ <input
+ ref={this._searchRef}
+ style={{ color: 'black' }}
+ className="contextMenu-item contextMenu-description search"
+ type="text"
+ placeholder="Filter Menu..."
+ value={this._searchString}
+ onKeyDown={this.onKeyDown}
+ onChange={this.onChange}
+ // eslint-disable-next-line jsx-a11y/no-autofocus
+ autoFocus
+ />
</span>
- <input
- ref={this._searchRef}
- style={{ color: 'black' }}
- className="contextMenu-item contextMenu-description search"
- type="text"
- placeholder="Filter Menu..."
- value={this._searchString}
- onKeyDown={this.onKeyDown}
- onChange={this.onChange}
- // eslint-disable-next-line jsx-a11y/no-autofocus
- autoFocus
- />
- </span>
- )}
- {this.menuItems}
+ )}
+ {this.menuItems}
+ </div>
</div>
);
}
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<ContextMenuProps &
render() {
if ('event' in this._props) {
return (
- <div className={'contextMenu-item' + (this._props.selected ? ' contextMenu-itemSelected' : '')} onPointerDown={this.handleEvent}>
+ <div className={'contextMenu-item' + (this._props.selected ? ' contextMenu-itemSelected' : '')} onPointerDown={this.handleEvent} >
{this._props.icon ? <span className="contextMenu-item-icon-background">{this.isJSXElement(this._props.icon) ? this._props.icon : <FontAwesomeIcon icon={this._props.icon} size="sm" />}</span> : null}
<div className="contextMenu-description">{this._props.description.replace(':', '')}</div>
<div
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d4467e536..9c350afc0 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -88,6 +88,7 @@ export class MainView extends ObservableReactComponent<{}> {
public static Live: boolean = false;
private _docBtnRef = React.createRef<HTMLDivElement>();
+ @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<PropertiesViewProps
set colorFil(value) { this.selectedDoc && (this.selectedDoc[DocData].fillColor = value || undefined); } // prettier-ignore
@computed get colorStk() { return StrCast(this.selectedDoc?.[DocData].color); } // prettier-ignore
set colorStk(value) { this.selectedDoc && (this.selectedDoc[DocData].color = value || undefined); } // prettier-ignore
+ @computed get borderColor() {
+ const doc = this.selectedDoc;
+ const layoutDoc = doc ? Doc.Layout(doc) : doc;
+ return StrCast(layoutDoc);
+ }
+ set borderColor(value) { this.selectedDoc && (this.selectedDoc[DocData].color = value || undefined); } // prettier-ignore
colorButton(value: string, type: string, setter: () => void) {
return (
@@ -898,6 +904,10 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
return this.colorPicker(this.colorStk, (color: string) => { this.colorStk = color; }); // prettier-ignore
}
+ @computed get borderColorPicker() {
+ return this.colorPicker(this.colorStk, (color: string) => { this.colorStk = color; }); // prettier-ignore
+ }
+
@computed get strokeAndFill() {
return (
<div>
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<Doc>, props: Opt<FieldViewProps &
const rounding = StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
return (doc?.[StrCast(doc?.layout_fieldKey)] instanceof Doc || doc?.isTemplateDoc) ? StrCast(doc._layout_borderRounding,rounding) : rounding;
}
+ // Doc.IsComicStyle(doc) &&
+ // renderDepth &&
+ // !doc?.layout_isSvg &&
+ //case StyleProp.
case StyleProp.BorderPath: {
- const borderPath = Doc.IsComicStyle(doc) &&
- renderDepth &&
- !doc?.layout_isSvg && { path: wavyBorderPath(PanelWidth?.() || 0, PanelHeight?.() || 0), fill: wavyBorderPath(PanelWidth?.() || 0, PanelHeight?.() || 0, 0.08), width: 3 };
+ const borderPath = doc?.type === 'image' && { path: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), NumCast(layoutDoc?._layout_borderWidth)/2), fill: wavyBorderPath(doc, NumCast(doc._width), NumCast(doc._height), 0.08), width: 3 };
return !borderPath
? null
: {
@@ -200,7 +213,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
jsx: (
<div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
<svg style={{ overflow: 'visible', height: '100%' }} viewBox={`0 0 ${PanelWidth?.()} ${PanelHeight?.()}`}>
- <path d={borderPath.path} style={{ stroke: 'black', fill: 'transparent', strokeWidth: borderPath.width }} />
+ <path d={borderPath.path} style={{ stroke: StrCast(layoutDoc?._layout_borderColor), fill: 'transparent', strokeWidth: `${StrCast(layoutDoc?._layout_borderWidth)}px` }} />
</svg>
</div>
),
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<FieldViewProps & Document
moreItems.push({ description: 'Make View of Metadata Field', event: () => 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<FieldViewProps & Document
return (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
+ // <div style={{position: 'relative'}}>
+ // <div className='docView-border-top' style={{width: `${this.layoutDoc._width}px`, height: '100px', backgroundColor: 'black'}}/>
+ // <div className='docView-border-right' style={{position: 'absolute', right: '-10px', width: '10px', height: `${this.layoutDoc._height}px`, backgroundColor: 'black'}}/>
+ // <div className='docView-border-left' style={{position: 'absolute', left: '-10px', width: '10px', height: `${this.layoutDoc._height}px`, backgroundColor: 'black'}}/>
+ // <div className='docView-border-bottom' style={{position: 'absolute', bottom: '-10px', height: '100px', width: `${this.layoutDoc._width}px`, backgroundColor: 'black'}}/>
<div
- 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}
- </div>
+ 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}
+ </div>
+ // </div>
);
}