1
0
Fork 0
mirror of synced 2024-07-14 10:45:51 +12:00

Move new row component to top, automatically invert cell renderers when required

This commit is contained in:
Andrew Kingston 2023-03-31 17:37:59 +01:00
parent 7050c6713a
commit a0299d4c7c
17 changed files with 331 additions and 62 deletions

View file

@ -355,6 +355,9 @@
input[type="file"] {
display: none;
}
.compact .spectrum-Dropzone {
padding: 6px 0 !important;
}
.gallery {
display: flex;
@ -381,7 +384,14 @@
}
.compact .placeholder,
.compact img {
margin: 12px 16px;
margin: 10px 16px;
}
.compact img {
height: 90px;
}
.compact .gallery {
padding: 6px 10px;
margin-bottom: 8px;
}
.title {
display: flex;

View file

@ -125,7 +125,7 @@
<div class="sort-indicator">
<Icon
size="S"
name={$sort.order === "descending" ? "ChevronDown" : "ChevronUp"}
name={$sort.order === "descending" ? "SortOrderDown" : "SortOrderUp"}
color="var(--spectrum-global-color-gray-600)"
/>
</div>

View file

@ -158,10 +158,11 @@
user-select: none;
}
.arrow {
border-right: 2px solid var(--spectrum-global-color-blue-400);
/*border-right: 2px solid var(--spectrum-global-color-blue-400);*/
position: absolute;
right: 0;
top: 2px;
top: 0;
height: 100%;
bottom: 2px;
padding: 0 6px 0 16px;
display: grid;
@ -182,7 +183,7 @@
box-shadow: 0 0 8px 4px rgba(0, 0, 0, 0.15);
justify-content: flex-start;
align-items: stretch;
max-height: calc(5 * var(--cell-height) + 1px);
max-height: var(--max-cell-render-height);
overflow-y: auto;
border: var(--cell-border);
}

View file

@ -293,7 +293,7 @@
left: 0;
min-width: 100%;
max-width: calc(100% + 240px);
max-height: calc(var(--cell-height) + 240px);
max-height: var(--max-cell-render-height);
background: var(--cell-background);
border: var(--cell-border);
box-shadow: 0 0 8px 4px rgba(0, 0, 0, 0.15);

View file

@ -68,16 +68,34 @@
position: relative;
width: 0;
}
.cell.selected:after,
.cell.error:after,
.cell.selected-other:not(.selected):after {
content: " ";
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
border: 2px solid transparent;
pointer-events: none;
border-radius: 2px;
box-sizing: border-box;
}
.cell.selected {
box-shadow: inset 0 0 0 2px var(--spectrum-global-color-blue-400);
z-index: 2;
}
.cell.error {
box-shadow: inset 0 0 0 2px var(--spectrum-global-color-red-400);
.cell.selected:after {
border-color: var(--spectrum-global-color-blue-400);
}
.cell.error:after {
border-color: var(--spectrum-global-color-red-400);
}
.cell.selected-other:not(.selected) {
z-index: 1;
box-shadow: inset 0 0 0 2px var(--user-color);
}
.cell.selected-other:not(.selected):after {
border-color: var(--spectrum-global-color-red-400);
}
.cell:not(.selected) {
user-select: none;
@ -112,7 +130,8 @@
.label {
position: absolute;
bottom: 100%;
padding: 1px 4px;
margin: 0 0 -2px 0;
padding: 1px 4px 3px 4px;
background: var(--user-color);
border-radius: 2px 2px 0 0;
display: none;
@ -129,7 +148,8 @@
bottom: auto;
top: 100%;
border-radius: 0 0 2px 2px;
padding: 0 4px 2px 4px;
padding: 2px 4px 2px 4px;
margin: -2px 0 0 0;
}
.cell:hover .label {
display: block;

View file

@ -1,38 +1,16 @@
<script>
import { Icon } from "@budibase/bbui"
import { ActionButton } from "@budibase/bbui"
import { getContext } from "svelte"
const { dispatch, columns, ui } = getContext("sheet")
const addRow = () => {
ui.actions.blur()
dispatch("add-row")
}
const { dispatch, columns, stickyColumn } = getContext("sheet")
</script>
{#if $columns.length}
<div class="add-component" on:click={addRow}>
<Icon size="XL" name="Add" />
</div>
{/if}
<style>
.add-component {
position: absolute;
bottom: calc(20px + var(--spacing-l));
right: calc(20px + var(--spacing-xl));
width: 60px;
height: 60px;
border-radius: 50%;
background: var(--spectrum-global-color-blue-500);
display: grid;
place-items: center;
color: white;
box-shadow: 1px 3px 8px 0 rgba(0, 0, 0, 0.3);
cursor: pointer;
transition: transform ease-out 300ms, background ease-out 130ms;
}
.add-component:hover {
background: var(--spectrum-global-color-blue-600);
}
</style>
<ActionButton
icon="Add"
quiet
size="M"
on:click={() => dispatch("add-row-inline")}
disabled={!$columns.length && !$stickyColumn}
>
Create row
</ActionButton>

View file

@ -32,7 +32,7 @@
background: var(--background);
border-bottom: var(--cell-border);
position: relative;
z-index: 1;
z-index: 2;
height: var(--cell-height);
}
.row {

View file

@ -0,0 +1,242 @@
<script>
import SheetCell from "../cells/SheetCell.svelte"
import { getContext, onMount } from "svelte"
import { Icon, Button } from "@budibase/bbui"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import DataCell from "../cells/DataCell.svelte"
const {
renderedColumns,
hoveredRowId,
selectedCellId,
stickyColumn,
gutterWidth,
scroll,
config,
dispatch,
visibleColumns,
rows,
wheel,
showHScrollbar,
tableId,
subscribe,
selectedCellAPI,
} = getContext("sheet")
let isAdding = false
let newRow = {}
let touched = false
$: firstColumn = $stickyColumn || $visibleColumns[0]
$: rowHovered = $hoveredRowId === "new"
$: containsSelectedCell = $selectedCellId?.startsWith("new-")
$: width = gutterWidth + ($stickyColumn?.width || 0)
$: scrollLeft = $scroll.left
$: $tableId, (isAdding = false)
const addRow = async () => {
const savedRow = await rows.actions.addRow(newRow, 0)
if (savedRow && firstColumn) {
$selectedCellId = `${savedRow._id}-${firstColumn.name}`
isAdding = false
}
}
const cancel = () => {
isAdding = false
}
const startAdding = () => {
newRow = {}
isAdding = true
if (firstColumn) {
$selectedCellId = `new-${firstColumn.name}`
setTimeout(() => {
$selectedCellAPI?.focus()
}, 100)
}
}
const updateRow = (rowId, columnName, val) => {
touched = true
newRow[columnName] = val
}
const addViaModal = () => {
isAdding = false
dispatch("add-row")
}
onMount(() => subscribe("add-row-inline", startAdding))
</script>
<!-- Only show new row functionality if we have any columns -->
{#if firstColumn}
<div
class="container"
class:visible={isAdding}
on:wheel={wheel.actions.handleWheel}
>
<div class="content" class:above-scrollbar={$showHScrollbar}>
<div
class="new-row"
on:mouseenter={() => ($hoveredRowId = "new")}
on:mouseleave={() => ($hoveredRowId = null)}
>
<div
class="sticky-column"
style="flex: 0 0 {width}px"
class:scrolled={scrollLeft > 0}
>
<SheetCell
width={gutterWidth}
{rowHovered}
rowSelected={containsSelectedCell}
>
<div class="gutter">
<div class="number">1</div>
{#if $config.allowExpandRows}
<Icon
name="Maximize"
size="S"
hoverable
on:click={addViaModal}
/>
{/if}
</div>
</SheetCell>
{#if $stickyColumn}
{@const cellId = `new-${$stickyColumn.name}`}
<DataCell
{cellId}
column={$stickyColumn}
row={newRow}
{rowHovered}
selected={$selectedCellId === cellId}
rowSelected={containsSelectedCell}
width={$stickyColumn.width}
{updateRow}
/>
{/if}
</div>
<SheetScrollWrapper scrollVertically={false}>
<div class="row">
{#each $renderedColumns as column}
{@const cellId = `new-${column.name}`}
<DataCell
{cellId}
{column}
row={newRow}
{rowHovered}
selected={$selectedCellId === cellId}
rowSelected={containsSelectedCell}
width={column.width}
{updateRow}
/>
{/each}
</div>
</SheetScrollWrapper>
</div>
</div>
<div class="buttons">
<Button size="M" cta on:click={addRow}>Save</Button>
<Button size="M" secondary newStyles on:click={cancel}>Cancel</Button>
</div>
</div>
{/if}
<style>
.container {
pointer-events: none;
position: absolute;
top: var(--cell-height);
transform: translateY(-100%);
z-index: 1;
transition: transform 130ms ease-out;
background: linear-gradient(
to bottom,
var(--cell-background) 20%,
transparent 100%
);
width: 100%;
padding-bottom: 64px;
display: flex;
flex-direction: column;
align-items: stretch;
}
.container.visible {
transform: translateY(0);
}
.content {
pointer-events: all;
background: var(--background);
border-bottom: var(--cell-border);
}
.new-row {
display: flex;
bottom: 0;
left: 0;
width: 100%;
transition: margin-bottom 130ms ease-out;
}
.new-row.visible {
margin-bottom: 0;
}
.new-row :global(.cell) {
--cell-background: var(--background) !important;
border-bottom: none;
}
.sticky-column {
display: flex;
z-index: 1;
}
/* Don't show borders between cells in the sticky column */
.sticky-column :global(.cell:not(:last-child)) {
border-right: none;
}
.row {
width: 0;
display: flex;
}
/* Add shadow when scrolled */
.sticky.scrolled :global(.cell:last-child:after) {
content: " ";
position: absolute;
width: 10px;
height: 100%;
left: 100%;
background: linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent);
}
/* Styles for gutter */
.gutter {
flex: 1 1 auto;
display: grid;
align-items: center;
padding: var(--cell-padding);
grid-template-columns: 1fr auto;
gap: var(--cell-spacing);
}
/* Floating buttons */
.buttons {
display: flex;
flex-direction: row;
gap: 8px;
margin: 16px 0 0 16px;
pointer-events: all;
align-self: flex-start;
}
.number {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
color: var(--spectrum-global-color-gray-500);
}
</style>

View file

@ -27,7 +27,8 @@
import KeyboardManager from "../overlays/KeyboardManager.svelte"
import { clickOutside } from "@budibase/bbui"
import SheetControls from "./SheetControls.svelte"
import NewRow from "./NewRow.svelte"
import NewRowTop from "./NewRowTop.svelte"
import { MaxCellRenderHeight } from "../lib/constants"
export let API
export let tableId
@ -108,12 +109,12 @@
id="sheet-{rand}"
class:is-resizing={$isResizing}
class:is-reordering={$isReordering}
style="--cell-height:{cellHeight}px; --gutter-width:{gutterWidth}px;"
style="--cell-height:{cellHeight}px; --gutter-width:{gutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px;"
>
<div class="controls">
<div class="controls-left">
<slot name="controls" />
<SheetControls />
<slot name="controls" />
</div>
<div class="controls-right">
<DeleteButton />
@ -129,7 +130,8 @@
<SheetBody />
</div>
{#if $config.allowAddRows}
<NewRow />
<!-- <NewRow />-->
<NewRowTop />
{/if}
<ResizeOverlay />
<ScrollOverlay />

View file

@ -2,11 +2,17 @@
import { getContext, onMount } from "svelte"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import SheetRow from "./SheetRow.svelte"
import { MaxCellRenderHeight } from "../lib/constants"
const { bounds, renderedRows } = getContext("sheet")
const { bounds, renderedRows, visualRowCapacity, cellHeight } =
getContext("sheet")
let body
$: inversionIdx =
$visualRowCapacity - Math.ceil(MaxCellRenderHeight / cellHeight) - 2
$: console.log(inversionIdx)
onMount(() => {
// Observe and record the height of the body
const observer = new ResizeObserver(() => {
@ -22,7 +28,7 @@
<div bind:this={body} class="sheet-body">
<SheetScrollWrapper>
{#each $renderedRows as row, idx}
<SheetRow {row} {idx} />
<SheetRow {row} {idx} invert={idx >= inversionIdx} />
{/each}
</SheetScrollWrapper>
</div>

View file

@ -1,7 +1,9 @@
<script>
import SortButton from "../controls/SortButton.svelte"
import HideColumnsButton from "../controls/HideColumnsButton.svelte"
import AddRowButton from "../controls/AddRowButton.svelte"
</script>
<AddRowButton />
<HideColumnsButton />
<SortButton />

View file

@ -4,6 +4,7 @@
export let row
export let idx
export let invert = false
const {
selectedCellId,
@ -40,6 +41,7 @@
{cellId}
{column}
{row}
{invert}
/>
{/each}
</div>

View file

@ -164,12 +164,12 @@
/* Add shadow when scrolled */
.sticky-column.scrolled :global(.cell:last-child:after) {
content: " ";
position: absolute;
width: 10px;
height: 100%;
left: 100%;
background: linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent);
/*content: " ";*/
/*position: absolute;*/
/*width: 10px;*/
/*height: 100%;*/
/*left: 100%;*/
/*background: linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent);*/
}
/* Don't show borders between cells in the sticky column */
@ -179,7 +179,7 @@
.header {
position: relative;
z-index: 2;
z-index: 3;
}
.header :global(.cell) {
background: var(--spectrum-global-color-gray-100);

View file

@ -0,0 +1 @@
export const MaxCellRenderHeight = 216

View file

@ -12,7 +12,7 @@ export const createMaxScrollStores = context => {
selectedCellId,
gutterWidth,
} = context
const padding = 255
const padding = 264
// Memoize store primitives
const scrollTop = derived(scroll, $scroll => $scroll.top, 0)

View file

@ -136,7 +136,7 @@ export const createRowsStore = context => {
} else {
handleNewRows([newRow])
}
notifications.success("Row added successfully")
notifications.success("Row created successfully")
return newRow
} catch (error) {
notifications.error(`Error adding row: ${error?.message}`)

View file

@ -77,5 +77,10 @@ export const createViewportStores = context => {
[]
)
return { scrolledRowCount, visualRowCapacity, renderedRows, renderedColumns }
return {
scrolledRowCount,
visualRowCapacity,
renderedRows,
renderedColumns,
}
}