aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2020-02-07 04:27:59 -0500
committerSam Wilkins <samwilkins333@gmail.com>2020-02-07 04:27:59 -0500
commit703bad5d9f3c6e385fc6f7c4db3b237c0d41401f (patch)
tree7bb66748a83e76759bc7d2c3d9d8e4bf6aea954b
parent4eba9ccc46ac6a1ad346ce5027b098a8a5b838c4 (diff)
parent9f82ece7c763ba4a054d86a715311e0280fcb79f (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web
-rw-r--r--src/Utils.ts2
-rw-r--r--src/client/views/collections/CollectionStackingView.scss1
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx19
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx29
-rw-r--r--src/client/views/collections/CollectionTimeView.scss5
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx39
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx37
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx1
10 files changed, 95 insertions, 60 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index 9e3db9e06..0fa33dcb7 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -363,7 +363,7 @@ export function percent2frac(percent: string) {
return Number(percent.substr(0, percent.length - 1)) / 100;
}
-export function numberRange(num: number) { return Array.from(Array(num)).map((v, i) => i); }
+export function numberRange(num: number) { return num > 0 && num < 1000 ? Array.from(Array(num)).map((v, i) => i) : []; }
export function returnTransparent() { return "transparent"; }
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 843c743db..293dc5414 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -19,6 +19,7 @@
position: absolute;
top: 0;
overflow-y: auto;
+ overflow-x: hidden;
flex-wrap: wrap;
transition: top .5s;
>div {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 91c7ca76e..e04f4e8a6 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -40,8 +40,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
@computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
@computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
@computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout); }
- @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * this.gridGap); }
- @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 2 * this.gridGap)); }
+ @computed get xMargin() { return NumCast(this.props.Document._xMargin, 0); }// 2 * this.gridGap); }
+ @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); }
@computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); }
@computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); }
@computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
@@ -52,11 +52,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
@computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
- children(docs: Doc[]) {
+ children(docs: Doc[], columns?: number) {
this._docXfs.length = 0;
return docs.map((d, i) => {
- const width = () => Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
const height = () => this.getDocHeight(d);
+ const width = () => (this.widthScale && !columns ? this.widthScale : 1) * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
const dref = React.createRef<HTMLDivElement>();
const dxf = () => this.getDocTransform(d, dref.current!);
this._docXfs.push({ dxf: dxf, width: width, height: height });
@@ -377,6 +377,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]));
}
+ @computed get heightScale() {
+ return Math.min(this.props.Document[WidthSym]() / this.props.PanelWidth(), this.props.Document[HeightSym]() / this.props.PanelHeight());
+ }
+ @computed get widthScale() {
+ return StrCast(this.props.Document.title).includes("slide") || true ? this.heightScale : undefined;
+ }
render() {
TraceMobx();
const editableViewProps = {
@@ -391,8 +397,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
style={{
overflowY: this.props.active() ? "auto" : "hidden",
transform: `scale(${Math.min(1, this.props.PanelHeight() / this.layoutDoc[HeightSym]())})`,
- height: `${Math.max(100, 100 * 1 / Math.min(this.props.PanelWidth() / this.layoutDoc[WidthSym](), this.props.PanelHeight() / this.layoutDoc[HeightSym]()))}%`,
- transformOrigin: "top"
+ height: `${Math.max(100, 100 * this.heightScale)}%`,
+ width: this.widthScale ? `${Math.max(100, 100 * this.widthScale)}%` : undefined,
+ transformOrigin: this.widthScale ? "top left" : "top",
}}
onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
onDrop={this.onDrop.bind(this)}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index b81b1f31d..21982f1ca 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -407,7 +407,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
gridTemplateColumns: singleColumn ? undefined : templatecols,
gridAutoRows: singleColumn ? undefined : "0px"
}}>
- {this.props.parent.children(this.props.docList)}
+ {this.props.parent.children(this.props.docList, uniqueHeadings.length)}
{singleColumn ? (null) : this.props.parent.columnDragger}
</div>
{(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ?
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a2700e75a..e0e99d635 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -111,34 +111,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
get childDocs() {
const docs = DocListCast(this.dataField);
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
- const viewedDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
- const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []);
- const clusters: { [key: string]: { [value: string]: string } } = {};
- for (let i = 0; i < docFilters.length; i += 3) {
- const [key, value, modifiers] = docFilters.slice(i, i + 3);
- const cluster = clusters[key];
- if (!cluster) {
- const child: { [value: string]: string } = {};
- child[value] = modifiers;
- clusters[key] = child;
- } else {
- cluster[value] = modifiers;
- }
- }
- const filteredDocs = docFilters.length ? viewedDocs.filter(d => {
- for (const key of Object.keys(clusters)) {
- const cluster = clusters[key];
- const satisfiesFacet = Object.keys(cluster).some(inner => {
- const modifier = cluster[inner];
- return (modifier === "x") !== Doc.matchFieldValue(d, key, inner);
- });
- if (!satisfiesFacet) {
- return false;
- }
- }
- return true;
- }) : viewedDocs;
- return filteredDocs;
+ return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
}
@action
diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss
index df5057b5b..a5ce73a92 100644
--- a/src/client/views/collections/CollectionTimeView.scss
+++ b/src/client/views/collections/CollectionTimeView.scss
@@ -5,6 +5,11 @@
height: 100%;
width: 100%;
overflow: hidden;
+ .collectionTimeView-backBtn {
+ background: green;
+ display: inline;
+ margin-right: 20px;
+ }
.collectionFreeform-customText {
text-align: left;
}
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index fb36a1b0c..0c1f93829 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,27 +1,27 @@
import { faEdit } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, observable, trace } from "mobx";
+import { action, computed, observable, trace } from "mobx";
import { observer } from "mobx-react";
import { Set } from "typescript-collections";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field } from "../../../new_fields/Doc";
import { List } from "../../../new_fields/List";
+import { RichTextField } from "../../../new_fields/RichTextField";
import { listSpec } from "../../../new_fields/Schema";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { Docs } from "../../documents/Documents";
+import { Scripting } from "../../util/Scripting";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
import { EditableView } from "../EditableView";
import { anchorPoints, Flyout } from "../TemplateMenu";
+import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines";
import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import "./CollectionTimeView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { CollectionTreeView } from "./CollectionTreeView";
+import "./CollectionTimeView.scss";
import React = require("react");
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { RichTextField } from "../../../new_fields/RichTextField";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { Scripting } from "../../util/Scripting";
-import { ViewDefResult, ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines";
+import { CollectionTreeView } from "./CollectionTreeView";
+import { ObjectField } from "../../../new_fields/ObjectField";
@observer
export class CollectionTimeView extends CollectionSubView(doc => doc) {
@@ -289,7 +289,19 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
<div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} onContextMenu={this.specificMenu}
style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
<div className={"pivotKeyEntry"}>
- <EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
+ <button className="collectionTimeView-backBtn" style={{ width: 50, height: 20, background: "green" }}
+ onClick={action(() => {
+ let pfilterIndex = NumCast(this.props.Document._pfilterIndex);
+ if (pfilterIndex > 0) {
+ this.props.Document._docFilter = ObjectField.MakeCopy(this.props.Document["_pfilter" + --pfilterIndex] as ObjectField);
+ this.props.Document._pfilterIndex = pfilterIndex;
+ } else {
+ this.props.Document._docFilter = new List([]);
+ }
+ })}>
+ back
+ </button>
+ <EditableView {...newEditableViewProps} display={"inline"} menuCallback={this.menuCallback} />
</div>
{!this.props.isSelected() || this.props.PanelHeight() < 100 ? (null) :
<div className="collectionTimeView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this._facetWidth}px, 0px)` }} >
@@ -308,6 +320,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
}
Scripting.addGlobal(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
+ let pfilterIndex = NumCast(pivotDoc._pfilterIndex);
+ pivotDoc["_pfilter" + pfilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilter as ObjectField);
+ pivotDoc._pfilterIndex = ++pfilterIndex;
pivotDoc._docFilter = new List();
(bounds.payload as string[]).map(filterVal =>
Doc.setDocFilter(pivotDoc, StrCast(pivotDoc._pivotField), filterVal, "check"));
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index e354ad0af..95f7794bb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -36,7 +36,6 @@ export interface PoolData {
color?: string,
transition?: string,
highlight?: boolean,
- state?: any
}
export interface ViewDefResult {
@@ -71,19 +70,21 @@ interface pivotColumn {
filters: string[]
}
+
export function computePivotLayout(
poolData: Map<string, PoolData>,
pivotDoc: Doc,
childDocs: Doc[],
+ filterDocs: Doc[],
childPairs: { layout: Doc, data?: Doc }[],
panelDim: number[],
- viewDefsToJSX: (views: any) => ViewDefResult[]
+ viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
) {
const fieldKey = "data";
const pivotColumnGroups = new Map<FieldResult<Field>, pivotColumn>();
const pivotFieldKey = toLabel(pivotDoc._pivotField);
- for (const doc of childDocs) {
+ for (const doc of filterDocs) {
const val = Field.toString(doc[pivotFieldKey] as Field);
if (val) {
!pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val] });
@@ -179,7 +180,7 @@ export function computePivotLayout(
const dividers = sortedPivotKeys.map((key, i) =>
({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters }));
groupNames.push(...dividers);
- return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, []);
+ return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childDocs.filter(c => !filterDocs.includes(c)));
}
function toNumber(val: FieldResult<Field>) {
@@ -190,9 +191,10 @@ export function computeTimelineLayout(
poolData: Map<string, PoolData>,
pivotDoc: Doc,
childDocs: Doc[],
+ filterDocs: Doc[],
childPairs: { layout: Doc, data?: Doc }[],
panelDim: number[],
- viewDefsToJSX: (views: ViewDefBounds) => ViewDefResult[]
+ viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
) {
const fieldKey = "data";
const pivotDateGroups = new Map<number, Doc[]>();
@@ -212,7 +214,7 @@ export function computeTimelineLayout(
let minTime = Number.MAX_VALUE;
let maxTime = -Number.MAX_VALUE;
- childDocs.map(doc => {
+ filterDocs.map(doc => {
const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey])));
if (!(Number.isNaN(num) || (minTimeReq && num < minTimeReq) || (maxTimeReq && num > maxTimeReq))) {
!pivotDateGroups.get(num) && pivotDateGroups.set(num, []);
@@ -275,7 +277,7 @@ export function computeTimelineLayout(
}
const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1, payload: undefined };
- return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
+ return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider], childDocs.filter(c => !filterDocs.includes(c)));
function layoutDocsAtTime(keyDocs: Doc[], key: number) {
keyDocs.forEach(doc => {
@@ -298,7 +300,8 @@ export function computeTimelineLayout(
}
function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map<Doc, ViewDefBounds>,
- poolData: Map<string, PoolData>, viewDefsToJSX: (views: ViewDefBounds) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[]) {
+ poolData: Map<string, PoolData>, viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[],
+ extraDocs: Doc[]) {
const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds);
const docEles = childPairs.filter(d => docMap.get(d.layout)).map(pair => docMap.get(pair.layout) as ViewDefBounds);
@@ -323,6 +326,7 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos });
}
});
+ extraDocs.map(ed => poolData.set(ed[Id], { x: 0, y: 0, zIndex: -99 }));
return {
elements: viewDefsToJSX(extras.concat(groupNames.map(gname => ({
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ea3805b65..2518a4a55 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -7,7 +7,7 @@ import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } f
import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas";
import { Id } from "../../../../new_fields/FieldSymbols";
import { InkTool, InkField, InkData } from "../../../../new_fields/InkField";
-import { createSchema, makeInterface } from "../../../../new_fields/Schema";
+import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema";
import { ScriptField } from "../../../../new_fields/ScriptField";
import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../new_fields/Types";
import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
@@ -794,12 +794,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}.bind(this));
doTimelineLayout(poolData: Map<string, any>) {
- return computeTimelineLayout(poolData, this.props.Document, this.childDocs,
+ return computeTimelineLayout(poolData, this.props.Document, this.childDocs, this.filterDocs,
this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
}
doPivotLayout(poolData: Map<string, any>) {
- return computePivotLayout(poolData, this.props.Document, this.childDocs,
+ return computePivotLayout(poolData, this.props.Document, this.childDocs, this.filterDocs,
this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
}
@@ -812,7 +812,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => {
const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state });
- state = pos.state === undefined ? state : pos.state;
poolData.set(pair.layout[Id], pos);
});
return { elements: elements };
@@ -826,6 +825,36 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
return { newPool, computedElementData: this.doFreeformLayout(newPool) };
}
+
+ @computed get filterDocs() {
+ const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []);
+ const clusters: { [key: string]: { [value: string]: string } } = {};
+ for (let i = 0; i < docFilters.length; i += 3) {
+ const [key, value, modifiers] = docFilters.slice(i, i + 3);
+ const cluster = clusters[key];
+ if (!cluster) {
+ const child: { [value: string]: string } = {};
+ child[value] = modifiers;
+ clusters[key] = child;
+ } else {
+ cluster[value] = modifiers;
+ }
+ }
+ const filteredDocs = docFilters.length ? this.childDocs.filter(d => {
+ for (const key of Object.keys(clusters)) {
+ const cluster = clusters[key];
+ const satisfiesFacet = Object.keys(cluster).some(inner => {
+ const modifier = cluster[inner];
+ return (modifier === "x") !== Doc.matchFieldValue(d, key, inner);
+ });
+ if (!satisfiesFacet) {
+ return false;
+ }
+ }
+ return true;
+ }) : this.childDocs;
+ return filteredDocs;
+ }
get doLayoutComputation() {
const { newPool, computedElementData } = this.doInternalLayoutComputation;
runInAction(() =>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index f484b6115..3bceec45f 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -88,6 +88,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
width: this.width,
height: this.height,
zIndex: this.ZInd,
+ display: this.ZInd === -99 ? "none" : undefined,
pointerEvents: this.props.Document.isBackground ? "none" : undefined
}} >