diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte index 2a5211a253..020dc11ae8 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte @@ -96,32 +96,6 @@ }, ] - // Add grid layout settings if required - if (screen.props.layout === "grid") { - settings = settings.concat([ - { - key: "props.cols", - label: "Columns", - control: Stepper, - defaultValue: 24, - props: { - min: 2, - max: 50, - }, - }, - { - key: "props.rows", - label: "Rows", - control: Stepper, - defaultValue: 24, - props: { - min: 2, - max: 50, - }, - }, - ]) - } - return settings } diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 6f665a80d7..8ca9698bcf 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -145,32 +145,6 @@ ], "defaultValue": "flex" }, - { - "type": "number", - "label": "Columns", - "key": "cols", - "placeholder": 12, - "defaultValue": 12, - "min": 2, - "max": 50, - "dependsOn": { - "setting": "layout", - "value": "grid" - } - }, - { - "type": "number", - "label": "Rows", - "key": "rows", - "placeholder": 12, - "defaultValue": 12, - "min": 2, - "max": 50, - "dependsOn": { - "setting": "layout", - "value": "grid" - } - }, { "type": "select", "label": "Direction", diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index 9cfa74cbb0..34de8122c8 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -480,10 +480,10 @@ position: relative; padding: 32px; } - .main:has(.screenslot-dom > .component > .grid) { + /* .main:has(.screenslot-dom > .component > .grid) { padding-top: 0; padding-bottom: 0; - } + }*/ .layout--none .main { padding: 0; } diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index cfe6f7d7bf..b46e763277 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -2,19 +2,18 @@ import { getContext } from "svelte" const component = getContext("component") - const { styleable, builderStore } = getContext("sdk") + const { styleable } = getContext("sdk") const context = getContext("context") - export let cols = 12 - export let rows = 12 + const cols = 12 + const rowHeight = 24 let width let height - $: cols = cols || 12 - $: rows = rows || 12 $: mobile = $context.device.mobile $: empty = $component.empty + $: rows = Math.max(1, Math.floor(height / rowHeight)) $: colSize = width / cols $: rowSize = height / rows @@ -22,7 +21,6 @@
- {#if $builderStore.inBuilder} -
- {#each { length: cols * rows } as _} -
- {/each} -
- {/if} +
+ {#each { length: cols * rows } as _} +
+ {/each} +
{#if !empty} @@ -57,32 +53,53 @@ .grid { position: relative; height: 400px; - gap: 0; - } - .grid.builder { - background: var(--spectrum-alias-background-color-secondary); + --spacing: 10; } + .grid, .underlay { display: grid; grid-template-rows: repeat(var(--rows), 1fr); grid-template-columns: repeat(var(--cols), 1fr); + gap: 0; } .underlay { + display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; - border: 1px solid var(--spectrum-global-color-gray-900); - opacity: 0.07; + border-top: 1px solid var(--spectrum-global-color-gray-900); + border-left: 1px solid var(--spectrum-global-color-gray-900); + opacity: 0.1; pointer-events: none; } .underlay { z-index: 0; } .placeholder { - border: 1px solid var(--spectrum-global-color-gray-900); + border-bottom: 1px solid var(--spectrum-global-color-gray-900); + border-right: 1px solid var(--spectrum-global-color-gray-900); + } + + /* Highlight grid lines when resizing children */ + :global(.grid.highlight > .underlay) { + display: grid; + } + + /* Highlight sibling borders when resizing childern */ + :global(.grid.highlight > .component:not(.dragging):after) { + content: ""; + display: block; + position: absolute; + height: 100%; + width: 100%; + border: 1px solid var(--spectrum-global-color-static-blue-200); + pointer-events: none; + z-index: 1; + top: 0; + left: 0; } /* Ensure all top level children have grid styles applied */ @@ -90,6 +107,9 @@ display: flex; overflow: auto; pointer-events: all; + position: relative; + padding: 5px; + margin: 5px; /* On desktop, use desktop metadata and fall back to mobile */ /* Position vars */ @@ -98,7 +118,12 @@ --grid-desktop-col-end, var( --grid-mobile-col-end, - round(up, calc(var(--default-width) / var(--col-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-width)) / var(--col-size) + 1 + ) + ) ) ); --row-start: var(--grid-desktop-row-start, var(--grid-mobile-row-start, 1)); @@ -106,7 +131,12 @@ --grid-desktop-row-end, var( --grid-mobile-row-end, - round(up, calc(var(--default-height) / var(--row-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-height)) / var(--row-size) + 1 + ) + ) ) ); @@ -137,7 +167,12 @@ --grid-mobile-col-end, var( --grid-desktop-col-end, - round(up, calc(var(--default-width) / var(--col-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-width)) / var(--col-size) + 1 + ) + ) ) ); --row-start: var(--grid-mobile-row-start, var(--grid-desktop-row-start, 1)); @@ -145,7 +180,12 @@ --grid-mobile-row-end, var( --grid-desktop-row-end, - round(up, calc(var(--default-height) / var(--row-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-height)) / var(--row-size) + 1 + ) + ) ) ); diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index f723d9ad29..fe004982d3 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -4,7 +4,7 @@ import { Utils, memo } from "@budibase/frontend-core" import { isGridEvent, - getGridParentID, + getGridParent, GridParams, getGridVar, } from "utils/grid" @@ -62,6 +62,9 @@ const { startX, startY, rowStart, rowEnd, colStart, colEnd } = grid const domGrid = getDOMNode(gridId) + if (!domGrid) { + return + } const cols = parseInt(domGrid.dataset.cols) const rows = parseInt(domGrid.dataset.rows) const { width, height } = domGrid.getBoundingClientRect() @@ -107,7 +110,7 @@ } gridStyles.set(newStyles) } - }, 100) + }, 10) const handleEvent = e => { e.preventDefault() @@ -140,16 +143,20 @@ // Find grid parent const domComponent = getDOMNode(id) - const gridId = getGridParentID(domComponent) - if (!gridId) { + const domGrid = getGridParent(domComponent) + if (!domGrid) { return } + // Apply active class to grid + domComponent.parentNode.classList.add("dragging") + domGrid.classList.add("highlight") + // Update state dragInfo = { domTarget: e.target, id, - gridId, + gridId: domGrid.parentNode.dataset.id, mode, side, } @@ -168,22 +175,23 @@ const { id, gridId } = dragInfo const domComponent = getDOMNode(id) const domGrid = getDOMNode(gridId) + if (!domComponent || !domGrid) { + return + } const gridCols = parseInt(domGrid.dataset.cols) const gridRows = parseInt(domGrid.dataset.rows) const styles = getComputedStyle(domComponent.parentNode) - if (domGrid) { - dragInfo.grid = { - startX: e.clientX, - startY: e.clientY, + dragInfo.grid = { + startX: e.clientX, + startY: e.clientY, - // Ensure things are within limits - rowStart: minMax(styles["grid-row-start"], 1, gridRows), - rowEnd: minMax(styles["grid-row-end"], 2, gridRows + 1), - colStart: minMax(styles["grid-column-start"], 1, gridCols), - colEnd: minMax(styles["grid-column-end"], 2, gridCols + 1), - } - handleEvent(e) + // Ensure things are within limits + rowStart: minMax(styles["grid-row-start"], 1, gridRows), + rowEnd: minMax(styles["grid-row-end"], 2, gridRows + 1), + colStart: minMax(styles["grid-column-start"], 1, gridCols), + colEnd: minMax(styles["grid-column-end"], 2, gridCols + 1), } + handleEvent(e) } const onDragOver = e => { @@ -195,15 +203,26 @@ // Callback when drag stops (whether dropped or not) const stopDragging = async () => { + if (!dragInfo) { + return + } + const { id, gridId, domTarget } = dragInfo + // Save changes if ($gridStyles) { - await builderStore.actions.updateStyles($gridStyles, dragInfo.id) + await builderStore.actions.updateStyles($gridStyles, id) } - // Reset listener - if (dragInfo?.domTarget) { - dragInfo.domTarget.removeEventListener("dragend", stopDragging) + // Reset DOM + const domComponent = getDOMNode(id) + if (domComponent) { + domComponent.parentNode.classList.remove("dragging") } + const domGrid = getDOMNode(gridId) + if (domGrid) { + domGrid.classList.remove("highlight") + } + domTarget.removeEventListener("dragend", stopDragging) // Reset state dragInfo = null diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 1d80e49696..54c5e2c24f 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -60,8 +60,8 @@ export const isGridChild = node => { } // Gets the component ID of the closest parent grid -export const getGridParentID = node => { - return node?.parentNode?.closest(".grid")?.parentNode.dataset.id +export const getGridParent = node => { + return node?.parentNode?.closest(".grid") } // Svelte action to apply required class names and styles to our component