aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-03-05 15:38:03 -0500
committerbobzel <zzzman@gmail.com>2025-03-05 15:38:03 -0500
commit436b3def89ea955e2ff30fe8c2e9d15092e8c9a9 (patch)
tree29804bb08a5a5deaf9cfdee7a3f290ada85e2dc3
parentdb3bdb19ff7bc1c69c544797c05a6db3b72b1464 (diff)
fixed gridView to have margins. fixed gridView rowslider.
-rw-r--r--src/client/views/PropertiesView.tsx13
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.scss13
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx135
3 files changed, 84 insertions, 77 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 8e043baee..11adf7435 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -152,9 +152,16 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
return this.selectedDoc?.isGroup;
}
@computed get isStack() {
- return [CollectionViewType.Masonry, CollectionViewType.Multicolumn, CollectionViewType.Multirow, CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Card, CollectionViewType.Carousel].includes(
- this.selectedDoc?.type_collection as CollectionViewType
- );
+ return [
+ CollectionViewType.Masonry,
+ CollectionViewType.Multicolumn,
+ CollectionViewType.Multirow,
+ CollectionViewType.Stacking,
+ CollectionViewType.NoteTaking,
+ CollectionViewType.Card,
+ CollectionViewType.Carousel,
+ CollectionViewType.Grid,
+ ].includes(this.selectedDoc?.type_collection as CollectionViewType);
}
rtfWidth = () => (!this.selectedLayoutDoc ? 0 : Math.min(NumCast(this.selectedLayoutDoc?._width), this._props.width - 20));
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.scss b/src/client/views/collections/collectionGrid/CollectionGridView.scss
index 845b07c51..4edaf9745 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.scss
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.scss
@@ -21,11 +21,11 @@
width: 100%;
}
- .react-grid-item>.react-resizable-handle {
+ .react-grid-item > .react-resizable-handle {
z-index: 4; // doesn't work on prezi otherwise
}
- .react-grid-item>.react-resizable-handle::after {
+ .react-grid-item > .react-resizable-handle::after {
// grey so it can be seen on the audiobox
border-right: 2px solid slategrey;
border-bottom: 2px solid slategrey;
@@ -41,7 +41,6 @@
position: absolute;
height: 3;
left: 5;
- top: 30;
transform-origin: left;
transform: rotate(90deg);
outline: none;
@@ -103,7 +102,7 @@
span::before,
span::after {
- content: "";
+ content: '';
width: 50%;
position: relative;
display: inline-block;
@@ -128,10 +127,8 @@
}
}
}
-
}
-
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
@@ -140,6 +137,6 @@ input::-webkit-inner-spin-button {
}
/* Firefox */
-input[type=number] {
+input[type='number'] {
-moz-appearance: textfield;
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 6dffb80f1..80bf4bd12 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -9,7 +9,7 @@ import { emptyFunction } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { DragManager } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { undoable } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
import { DocumentView } from '../../nodes/DocumentView';
@@ -22,9 +22,9 @@ export class CollectionGridView extends CollectionSubView() {
private _containerRef: React.RefObject<HTMLDivElement> = React.createRef();
private _changeListenerDisposer: Opt<Lambda>; // listens for changes in this.childLayoutPairs
private _resetListenerDisposer: Opt<Lambda>; // listens for when the reset button is clicked
+ private _dropLocation: object = {}; // sets the drop location for external drops
@observable private _rowHeight: Opt<number> = undefined; // temporary store of row height to make change undoable
@observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll
- private dropLocation: object = {}; // sets the drop location for external drops
constructor(props: SubCollectionViewProps) {
super(props);
@@ -48,14 +48,20 @@ export class CollectionGridView extends CollectionSubView() {
}
@computed get colWidthPlusGap() {
- return (this._props.PanelWidth() - this.margin) / this.numCols;
+ return (this._props.PanelWidth() - 2 * this.xMargin - this.gridGap) / this.numCols;
}
@computed get rowHeightPlusGap() {
- return this.rowHeight + this.margin;
+ return this.rowHeight + this.gridGap;
}
- @computed get margin() {
- return NumCast(this.Document.margin, 10);
+ @computed get xMargin() {
+ return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth()));
+ }
+ @computed get yMargin() {
+ return this._props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
+ }
+ @computed get gridGap() {
+ return NumCast(this.Document._gridGap, 10);
} // sets the margin between grid nodes
@computed get flexGrid() {
@@ -77,10 +83,10 @@ export class CollectionGridView extends CollectionSubView() {
pairs.forEach((pair, i) => {
const existing = oldLayouts.find(l => l.i === pair.layout[Id]);
if (existing) newLayouts.push(existing);
- else if (Object.keys(this.dropLocation).length) {
+ else if (Object.keys(this._dropLocation).length) {
// external drop
- this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this.dropLocation as { x: number; y: number }, !this.flexGrid));
- this.dropLocation = {};
+ this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this._dropLocation as { x: number; y: number }, !this.flexGrid));
+ this._dropLocation = {};
} else {
// internal drop
this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this.unflexedPosition(i), !this.flexGrid));
@@ -115,30 +121,29 @@ export class CollectionGridView extends CollectionSubView() {
* @returns the default location of the grid node (i.e. when the grid is static)
* @param index
*/
- unflexedPosition(index: number): Omit<Layout, 'i'> {
- return {
- x: (index % (Math.floor(this.numCols / this.defaultW) || 1)) * this.defaultW,
- y: Math.floor(index / (Math.floor(this.numCols / this.defaultH) || 1)) * this.defaultH,
- w: this.defaultW,
- h: this.defaultH,
- static: true,
- };
- }
+ unflexedPosition = (index: number): Omit<Layout, 'i'> => ({
+ x: (index % (Math.floor(this.numCols / this.defaultW) || 1)) * this.defaultW,
+ y: Math.floor(index / (Math.floor(this.numCols / this.defaultH) || 1)) * this.defaultH,
+ w: this.defaultW,
+ h: this.defaultH,
+ static: true,
+ });
/**
* Maps the x- and y- coordinates of the event to a grid cell.
*/
- screenToCell(sx: number, sy: number) {
- const pt = this.ScreenToLocalBoxXf().transformPoint(sx, sy);
- const x = Math.floor(pt[0] / this.colWidthPlusGap);
- const y = Math.floor((pt[1] + this._scroll) / this.rowHeight);
+ screenToCell = (sx: number, sy: number) => {
+ const [ptx, pty] = this.ScreenToLocalBoxXf().transformPoint(sx, sy);
+ const x = Math.floor((ptx + this.xMargin) / this.colWidthPlusGap);
+ const y = Math.floor((pty + this.yMargin + this._scroll) / this.rowHeight);
return { x, y };
- }
+ };
/**
* Creates a layout object for a grid item
*/
- makeLayoutItem = (doc: Doc, pos: { x: number; y: number }, Static: boolean = false, w: number = this.defaultW, h: number = this.defaultH) => ({ i: doc[Id], w, h, x: pos.x, y: pos.y, static: Static });
+ makeLayoutItem = (doc: Doc, pos: { x: number; y: number }, Static: boolean = false, w: number = this.defaultW, h: number = this.defaultH) =>
+ ({ i: doc[Id], w, h, x: pos.x, y: pos.y, static: Static }); // prettier-ignore
/**
* Adds a layout to the list of layouts.
@@ -152,9 +157,9 @@ export class CollectionGridView extends CollectionSubView() {
/**
* @returns the transform that will correctly place the document decorations box.
*/
- private lookupIndividualTransform = (layout: Layout) => {
+ lookupIndividualTransform = (layout: Layout) => {
const xypos = this.flexGrid ? layout : this.unflexedPosition(this.renderedLayoutList.findIndex(l => l.i === layout.i));
- const pos = { x: xypos.x * this.colWidthPlusGap + this.margin, y: xypos.y * this.rowHeightPlusGap + this.margin - this._scroll };
+ const pos = { x: xypos.x * this.colWidthPlusGap + this.gridGap + this.xMargin, y: xypos.y * this.rowHeightPlusGap + this.gridGap - this._scroll + this.yMargin };
return this.ScreenToLocalBoxXf().translate(-pos.x, -pos.y);
};
@@ -169,9 +174,9 @@ export class CollectionGridView extends CollectionSubView() {
/**
* Stores the layout list on the Document as JSON
*/
- setLayoutList(layouts: Layout[]) {
+ setLayoutList = (layouts: Layout[]) => {
this.Document.gridLayoutString = JSON.stringify(layouts);
- }
+ };
isContentActive = () => this._props.isSelected() || this._props.isContentActive();
isChildContentActive = () => (this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive)) ? true : undefined);
@@ -183,29 +188,27 @@ export class CollectionGridView extends CollectionSubView() {
* @param height
* @returns the `ContentFittingDocumentView` of the node
*/
- getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
- return (
- <DocumentView
- {...this._props}
- Document={layout}
- TemplateDataDocument={layout.resolvedDataDoc as Doc}
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- fitWidth={this._props.childLayoutFitWidth}
- containerViewPath={this.childContainerViewPath}
- renderDepth={this._props.renderDepth + 1}
- isContentActive={this.isChildContentActive}
- PanelWidth={width}
- PanelHeight={height}
- ScreenToLocalTransform={dxf}
- setContentViewBox={emptyFunction}
- whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- onClickScript={this.onChildClickHandler}
- dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
- showTags={BoolCast(this.layoutDoc.showChildTags) || BoolCast(this.Document._layout_showTags)}
- />
- );
- }
+ getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => (
+ <DocumentView
+ {...this._props}
+ Document={layout}
+ TemplateDataDocument={layout.resolvedDataDoc as Doc}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ fitWidth={this._props.childLayoutFitWidth}
+ containerViewPath={this.childContainerViewPath}
+ renderDepth={this._props.renderDepth + 1}
+ isContentActive={this.isChildContentActive}
+ PanelWidth={width}
+ PanelHeight={height}
+ ScreenToLocalTransform={dxf}
+ setContentViewBox={emptyFunction}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ onClickScript={this.onChildClickHandler}
+ dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'}
+ showTags={BoolCast(this.layoutDoc.showChildTags) || BoolCast(this.Document._layout_showTags)}
+ />
+ );
/**
* Saves the layouts received from the Grid to the Document.
@@ -238,15 +241,14 @@ export class CollectionGridView extends CollectionSubView() {
* @returns a list of `ContentFittingDocumentView`s inside wrapper divs.
* The key of the wrapper div must be the same as the `i` value of the corresponding layout.
*/
- @computed
- private get contents(): JSX.Element[] {
+ @computed get contents(): JSX.Element[] {
const collector: JSX.Element[] = [];
if (this.renderedLayoutList.length === this.childLayoutPairs.length) {
this.renderedLayoutList.forEach(l => {
const child = this.childLayoutPairs.find(c => c.layout[Id] === l.i);
const dxf = () => this.lookupIndividualTransform(l);
- const width = () => (this.flexGrid ? l.w : this.defaultW) * this.colWidthPlusGap - this.margin;
- const height = () => (this.flexGrid ? l.h : this.defaultH) * this.rowHeightPlusGap - this.margin;
+ const width = () => (this.flexGrid ? l.w : this.defaultW) * this.colWidthPlusGap - this.gridGap;
+ const height = () => (this.flexGrid ? l.h : this.defaultH) * this.rowHeightPlusGap - this.gridGap;
child &&
collector.push(
<div key={child.layout[Id]} className={'document-wrapper' + (this.flexGrid && this._props.isSelected() ? '' : ' static')}>
@@ -295,7 +297,7 @@ export class CollectionGridView extends CollectionSubView() {
* Handles external drop of images/PDFs etc from outside Dash.
*/
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
- this.dropLocation = this.screenToCell(e.clientX, e.clientY);
+ this._dropLocation = this.screenToCell(e.clientX, e.clientY);
super.onExternalDrop(e, {});
};
@@ -316,12 +318,13 @@ export class CollectionGridView extends CollectionSubView() {
this,
e,
returnFalse,
- action(() => {
- undoable(() => {
+ undoable(
+ action(() => {
this.Document.gridRowHeight = this._rowHeight;
- }, 'changing row height')();
- this._rowHeight = undefined;
- }),
+ this._rowHeight = undefined;
+ }),
+ 'changing row height'
+ ),
emptyFunction,
false,
false
@@ -391,14 +394,14 @@ export class CollectionGridView extends CollectionSubView() {
<div
className="collectionGridView-gridContainer"
ref={this._containerRef}
- style={{ backgroundColor: StrCast(this.layoutDoc._backgroundColor, 'white') }}
+ style={{ backgroundColor: StrCast(this.layoutDoc._backgroundColor, 'white'), padding: `${this.yMargin} ${this.xMargin}` }}
onWheel={e => e.stopPropagation()}
onScroll={action(e => {
if (!this._props.isSelected()) e.currentTarget.scrollTop = this._scroll;
else this._scroll = e.currentTarget.scrollTop;
})}>
<Grid
- width={this._props.PanelWidth()}
+ width={this._props.PanelWidth() - 2 * this.xMargin}
nodeList={this.contents.length ? this.contents : null}
layout={this.contents.length ? this.renderedLayoutList : undefined}
childrenDraggable={!!this._props.isSelected()}
@@ -408,15 +411,15 @@ export class CollectionGridView extends CollectionSubView() {
transformScale={this.ScreenToLocalBoxXf().Scale}
compactType={this.compaction} // determines whether nodes should remain in position, be bound to the top, or to the left
preventCollision={BoolCast(this.Document.gridPreventCollision)} // determines whether nodes should move out of the way (i.e. collide) when other nodes are dragged over them
- margin={this.margin}
+ margin={this.gridGap}
/>
<input
className="rowHeightSlider"
type="range"
- style={{ width: this._props.PanelHeight() - 30 }}
+ style={{ width: this._props.PanelHeight() - 2 * this.yMargin }}
min={1}
value={this.rowHeight}
- max={this._props.PanelHeight() - 30}
+ max={this._props.PanelHeight() - 2 * this.yMargin}
onPointerDown={this.onSliderDown}
onChange={this.onSliderChange}
/>