Make sheet gutter width customisable

This commit is contained in:
Andrew Kingston 2023-03-30 09:19:39 +01:00
parent 09f4f210ee
commit 5640b2fa89
33 changed files with 120 additions and 88 deletions

View File

@ -1,3 +1,3 @@
export { default as SplitPage } from "./SplitPage.svelte" export { default as SplitPage } from "./SplitPage.svelte"
export { default as TestimonialPage } from "./TestimonialPage.svelte" export { default as TestimonialPage } from "./TestimonialPage.svelte"
export { default as Sheet } from "./sheet/Sheet.svelte" export { Sheet } from "./sheet"

View File

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

View File

@ -1,7 +1,7 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import SheetCell from "./SheetCell.svelte" import SheetCell from "./SheetCell.svelte"
import { getCellRenderer } from "../renderers" import { getCellRenderer } from "../lib/renderers"
const { rows, selectedCellId, menu, selectedCellAPI } = getContext("sheet") const { rows, selectedCellId, menu, selectedCellAPI } = getContext("sheet")

View File

@ -2,7 +2,7 @@
import { getContext } from "svelte" import { getContext } from "svelte"
import SheetCell from "./SheetCell.svelte" import SheetCell from "./SheetCell.svelte"
import { Icon, Popover, Menu, MenuItem } from "@budibase/bbui" import { Icon, Popover, Menu, MenuItem } from "@budibase/bbui"
import { getColumnIcon } from "../utils" import { getColumnIcon } from "../lib/utils"
export let column export let column
export let idx export let idx

View File

@ -1,6 +1,6 @@
<script> <script>
import { Icon } from "@budibase/bbui" import { Icon } from "@budibase/bbui"
import { getColor } from "../utils" import { getColor } from "../lib/utils"
import { onMount } from "svelte" import { onMount } from "svelte"
export let value export let value

View File

@ -1,5 +1,5 @@
<script> <script>
import { getColor } from "../utils" import { getColor } from "../lib/utils"
import { onMount, getContext } from "svelte" import { onMount, getContext } from "svelte"
import { Icon, Input } from "@budibase/bbui" import { Icon, Input } from "@budibase/bbui"
import { debounce } from "../../../utils/utils" import { debounce } from "../../../utils/utils"

View File

@ -0,0 +1 @@
export { default as Sheet } from "./layout/Sheet.svelte"

View File

@ -1,7 +1,7 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte" import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import HeaderCell from "./cells/HeaderCell.svelte" import HeaderCell from "../cells/HeaderCell.svelte"
import { Icon } from "@budibase/bbui" import { Icon } from "@budibase/bbui"
const { renderedColumns, dispatch, config, ui } = getContext("sheet") const { renderedColumns, dispatch, config, ui } = getContext("sheet")

View File

@ -1,9 +1,9 @@
<script> <script>
import SheetCell from "./cells/SheetCell.svelte" import SheetCell from "../cells/SheetCell.svelte"
import { getContext } from "svelte" import { getContext } from "svelte"
import { Icon } from "@budibase/bbui" import { Icon } from "@budibase/bbui"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte" import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import { getCellRenderer } from "./renderers" import { getCellRenderer } from "../lib/renderers"
const { const {
renderedColumns, renderedColumns,
@ -12,13 +12,14 @@
selectedCellId, selectedCellId,
reorder, reorder,
stickyColumn, stickyColumn,
gutterWidth,
} = getContext("sheet") } = getContext("sheet")
let isAdding = false let isAdding = false
let newRow = {} let newRow = {}
$: rowHovered = $hoveredRowId === "new" $: rowHovered = $hoveredRowId === "new"
$: width = 40 + ($stickyColumn?.width || 0) $: width = gutterWidth + ($stickyColumn?.width || 0)
const addRow = async field => { const addRow = async field => {
// const newRow = await rows.actions.addRow() // const newRow = await rows.actions.addRow()
@ -48,7 +49,7 @@
</div> </div>
{:else} {:else}
<div class="sticky" style="flex: 0 0 {width}px"> <div class="sticky" style="flex: 0 0 {width}px">
<SheetCell width="40" center> <SheetCell width={gutterWidth} center>
<Icon name="Add" size="S" /> <Icon name="Add" size="S" />
</SheetCell> </SheetCell>
{#if $stickyColumn} {#if $stickyColumn}
@ -116,7 +117,7 @@
background: var(--cell-background-hover); background: var(--cell-background-hover);
} }
.add .icon { .add .icon {
flex: 0 0 40px; flex: 0 0 var(--gutter-width);
display: grid; display: grid;
place-items: center; place-items: center;
} }

View File

@ -1,33 +1,33 @@
<script> <script>
import { setContext, onMount } from "svelte" import { setContext } from "svelte"
import { writable } from "svelte/store" import { writable } from "svelte/store"
import { createEventManagers } from "./events" import { createEventManagers } from "../lib/events"
import { createAPIClient } from "../../api" import { createAPIClient } from "../../../api"
import { createReorderStores } from "./stores/reorder" import { createReorderStores } from "../stores/reorder"
import { createViewportStores } from "./stores/viewport" import { createViewportStores } from "../stores/viewport"
import { createRowsStore } from "./stores/rows" import { createRowsStore } from "../stores/rows"
import { createColumnsStores } from "./stores/columns" import { createColumnsStores } from "../stores/columns"
import { createScrollStores } from "./stores/scroll" import { createScrollStores } from "../stores/scroll"
import { createBoundsStores } from "./stores/bounds" import { createBoundsStores } from "../stores/bounds"
import { createUIStores } from "./stores/ui" import { createUIStores } from "../stores/ui"
import { createUserStores } from "./stores/users" import { createUserStores } from "../stores/users"
import { createWebsocket } from "./websocket" import { createResizeStores } from "../stores/resize"
import { createResizeStores } from "./stores/resize" import { createMenuStores } from "../stores/menu"
import { createMenuStores } from "./stores/menu" import { createMaxScrollStores } from "../stores/max-scroll"
import { createMaxScrollStores } from "./stores/max-scroll" import { createPaginationStores } from "../stores/pagination"
import { createPaginationStores } from "./stores/pagination" import DeleteButton from "../controls/DeleteButton.svelte"
import DeleteButton from "./DeleteButton.svelte"
import SheetBody from "./SheetBody.svelte" import SheetBody from "./SheetBody.svelte"
import ResizeOverlay from "./ResizeOverlay.svelte" import ResizeOverlay from "../overlays/ResizeOverlay.svelte"
import HeaderRow from "./HeaderRow.svelte" import HeaderRow from "./HeaderRow.svelte"
import ScrollOverlay from "./ScrollOverlay.svelte" import ScrollOverlay from "../overlays/ScrollOverlay.svelte"
import MenuOverlay from "./MenuOverlay.svelte" import MenuOverlay from "../overlays/MenuOverlay.svelte"
import StickyColumn from "./StickyColumn.svelte" import StickyColumn from "./StickyColumn.svelte"
import UserAvatars from "./UserAvatars.svelte" import UserAvatars from "./UserAvatars.svelte"
import KeyboardManager from "./KeyboardManager.svelte" import KeyboardManager from "../overlays/KeyboardManager.svelte"
import { clickOutside } from "@budibase/bbui" import { clickOutside } from "@budibase/bbui"
import AddRowButton from "./AddRowButton.svelte" import AddRowButton from "../controls/AddRowButton.svelte"
import SheetControls from "./SheetControls.svelte" import SheetControls from "./SheetControls.svelte"
import SidePanel from "./SidePanel.svelte"
export let API export let API
export let tableId export let tableId
@ -38,6 +38,7 @@
// Sheet constants // Sheet constants
const cellHeight = 36 const cellHeight = 36
const gutterWidth = 80
const rand = Math.random() const rand = Math.random()
// State stores // State stores
@ -55,6 +56,7 @@
API: API || createAPIClient(), API: API || createAPIClient(),
rand, rand,
cellHeight, cellHeight,
gutterWidth,
config, config,
} }
context = { ...context, ...createEventManagers() } context = { ...context, ...createEventManagers() }
@ -98,7 +100,7 @@
id="sheet-{rand}" id="sheet-{rand}"
class:is-resizing={$isResizing} class:is-resizing={$isResizing}
class:is-reordering={$isReordering} class:is-reordering={$isReordering}
style="--cell-height:{cellHeight}px;" style="--cell-height:{cellHeight}px; --gutter-width:{gutterWidth}px;"
> >
<div class="controls"> <div class="controls">
<div class="controls-left"> <div class="controls-left">
@ -125,6 +127,7 @@
{/if} {/if}
</div> </div>
{/if} {/if}
<SidePanel />
<KeyboardManager /> <KeyboardManager />
</div> </div>

View File

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

View File

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import DataCell from "./cells/DataCell.svelte" import DataCell from "../cells/DataCell.svelte"
export let row export let row
export let idx export let idx

View File

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { domDebounce } from "../../utils/utils" import { domDebounce } from "../../../utils/utils"
const { const {
cellHeight, cellHeight,

View File

@ -0,0 +1,20 @@
<script>
import { getContext } from "svelte"
const { sidePanelRowId } = getContext("sheet")
$: visible = $sidePanelRowId != null
</script>
<div class="side-panel" class:visible>some content</div>
<style>
.side-panel {
width: 320px;
transform: translateX(100%);
transition: transform 130ms ease-out;
}
.side-panel.visible {
transform: translateX(0);
}
</style>

View File

@ -1,10 +1,10 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { Checkbox } from "@budibase/bbui" import { Checkbox } from "@budibase/bbui"
import SheetCell from "./cells/SheetCell.svelte" import SheetCell from "../cells/SheetCell.svelte"
import DataCell from "./cells/DataCell.svelte" import DataCell from "../cells/DataCell.svelte"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte" import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import HeaderCell from "./cells/HeaderCell.svelte" import HeaderCell from "../cells/HeaderCell.svelte"
const { const {
rows, rows,
@ -18,12 +18,13 @@
config, config,
selectedCellMap, selectedCellMap,
selectedCellRow, selectedCellRow,
gutterWidth,
} = getContext("sheet") } = getContext("sheet")
$: scrollLeft = $scroll.left $: scrollLeft = $scroll.left
$: rowCount = $rows.length $: rowCount = $rows.length
$: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length $: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
$: width = 40 + ($stickyColumn?.width || 0) $: width = gutterWidth + ($stickyColumn?.width || 0)
const selectAll = () => { const selectAll = () => {
const allSelected = selectedRowCount === rowCount const allSelected = selectedRowCount === rowCount
@ -59,7 +60,7 @@
> >
<div class="header row"> <div class="header row">
<SheetCell <SheetCell
width="40" width={gutterWidth}
on:click={$config.allowSelectRows && selectAll} on:click={$config.allowSelectRows && selectAll}
center center
> >
@ -90,7 +91,7 @@
<SheetCell <SheetCell
rowSelected={rowSelected || containsSelectedRow} rowSelected={rowSelected || containsSelectedRow}
{rowHovered} {rowHovered}
width="40" width={gutterWidth}
center center
> >
<div <div

View File

@ -0,0 +1,29 @@
import OptionsCell from "../cells/OptionsCell.svelte"
import DateCell from "../cells/DateCell.svelte"
import MultiSelectCell from "../cells/MultiSelectCell.svelte"
import NumberCell from "../cells/NumberCell.svelte"
import RelationshipCell from "../cells/RelationshipCell.svelte"
import TextCell from "../cells/TextCell.svelte"
import LongFormCell from "../cells/LongFormCell.svelte"
import BooleanCell from "../cells/BooleanCell.svelte"
import FormulaCell from "../cells/FormulaCell.svelte"
import JSONCell from "../cells/JSONCell.svelte"
import AttachmentCell from "../cells/AttachmentCell.svelte"
const TypeComponentMap = {
text: TextCell,
options: OptionsCell,
datetime: DateCell,
barcodeqr: TextCell,
longform: LongFormCell,
array: MultiSelectCell,
number: NumberCell,
boolean: BooleanCell,
attachment: AttachmentCell,
link: RelationshipCell,
formula: FormulaCell,
json: JSONCell,
}
export const getCellRenderer = column => {
return TypeComponentMap[column?.schema?.type] || TextCell
}

View File

@ -1,6 +1,6 @@
<script> <script>
import { getContext, onMount } from "svelte" import { getContext, onMount } from "svelte"
import { debounce } from "../../utils/utils" import { debounce } from "../../../utils/utils"
const { const {
rows, rows,

View File

@ -8,11 +8,12 @@
renderedColumns, renderedColumns,
stickyColumn, stickyColumn,
isReordering, isReordering,
gutterWidth,
} = getContext("sheet") } = getContext("sheet")
$: scrollLeft = $scroll.left $: scrollLeft = $scroll.left
$: cutoff = scrollLeft + 40 + ($columns[0]?.width || 0) $: cutoff = scrollLeft + gutterWidth + ($columns[0]?.width || 0)
$: offset = 40 + ($stickyColumn?.width || 0) $: offset = gutterWidth + ($stickyColumn?.width || 0)
$: column = $resize.column $: column = $resize.column
const getStyle = (column, offset, scrollLeft) => { const getStyle = (column, offset, scrollLeft) => {
@ -28,7 +29,7 @@
class:visible={column === $stickyColumn.name} class:visible={column === $stickyColumn.name}
on:mousedown={e => resize.actions.startResizing($stickyColumn, e)} on:mousedown={e => resize.actions.startResizing($stickyColumn, e)}
on:dblclick={() => resize.actions.resetSize($stickyColumn)} on:dblclick={() => resize.actions.resetSize($stickyColumn)}
style="left:{40 + $stickyColumn.width}px;" style="left:{gutterWidth + $stickyColumn.width}px;"
> >
<div class="resize-indicator" /> <div class="resize-indicator" />
</div> </div>

View File

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { domDebounce } from "../../utils/utils" import { domDebounce } from "../../../utils/utils"
const { const {
scroll, scroll,
@ -11,6 +11,7 @@
maxScrollTop, maxScrollTop,
contentWidth, contentWidth,
maxScrollLeft, maxScrollLeft,
gutterWidth,
} = getContext("sheet") } = getContext("sheet")
// Bar config // Bar config
@ -36,7 +37,7 @@
$: barTop = barOffset + cellHeight + availHeight * (scrollTop / $maxScrollTop) $: barTop = barOffset + cellHeight + availHeight * (scrollTop / $maxScrollTop)
// Calculate H scrollbar size and offset // Calculate H scrollbar size and offset
$: totalWidth = width + 40 + ($stickyColumn?.width || 0) $: totalWidth = width + gutterWidth + ($stickyColumn?.width || 0)
$: renderWidth = totalWidth - 2 * barOffset $: renderWidth = totalWidth - 2 * barOffset
$: barWidth = Math.max(50, (totalWidth / $contentWidth) * renderWidth) $: barWidth = Math.max(50, (totalWidth / $contentWidth) * renderWidth)
$: availWidth = renderWidth - barWidth $: availWidth = renderWidth - barWidth

View File

@ -1,29 +0,0 @@
import OptionsCell from "./cells/OptionsCell.svelte"
import DateCell from "./cells/DateCell.svelte"
import MultiSelectCell from "./cells/MultiSelectCell.svelte"
import NumberCell from "./cells/NumberCell.svelte"
import RelationshipCell from "./cells/RelationshipCell.svelte"
import TextCell from "./cells/TextCell.svelte"
import LongFormCell from "./cells/LongFormCell.svelte"
import BooleanCell from "./cells/BooleanCell.svelte"
import FormulaCell from "./cells/FormulaCell.svelte"
import JSONCell from "./cells/JSONCell.svelte"
import AttachmentCell from "./cells/AttachmentCell.svelte"
const TypeComponentMap = {
text: TextCell,
options: OptionsCell,
datetime: DateCell,
barcodeqr: TextCell,
longform: LongFormCell,
array: MultiSelectCell,
number: NumberCell,
boolean: BooleanCell,
attachment: AttachmentCell,
link: RelationshipCell,
formula: FormulaCell,
json: JSONCell,
}
export const getCellRenderer = column => {
return TypeComponentMap[column?.schema?.type] || TextCell
}

View File

@ -3,7 +3,7 @@ import { derived, get, writable } from "svelte/store"
export const DefaultColumnWidth = 200 export const DefaultColumnWidth = 200
export const createColumnsStores = context => { export const createColumnsStores = context => {
const { table } = context const { table, gutterWidth } = context
const columns = writable([]) const columns = writable([])
const stickyColumn = writable(null) const stickyColumn = writable(null)
@ -93,7 +93,7 @@ export const createColumnsStores = context => {
stickyColumn.set({ stickyColumn.set({
name: primaryDisplay, name: primaryDisplay,
width: existing?.width || DefaultColumnWidth, width: existing?.width || DefaultColumnWidth,
left: 40, left: gutterWidth,
schema: schema[primaryDisplay], schema: schema[primaryDisplay],
idx: "sticky", idx: "sticky",
}) })

View File

@ -10,6 +10,7 @@ export const createMaxScrollStores = context => {
scroll, scroll,
selectedCellRow, selectedCellRow,
selectedCellId, selectedCellId,
gutterWidth,
} = context } = context
const padding = 255 const padding = 255
@ -35,7 +36,7 @@ export const createMaxScrollStores = context => {
const contentWidth = derived( const contentWidth = derived(
[visibleColumns, stickyColumn], [visibleColumns, stickyColumn],
([$visibleColumns, $stickyColumn]) => { ([$visibleColumns, $stickyColumn]) => {
let width = 40 + padding + ($stickyColumn?.width || 0) let width = gutterWidth + padding + ($stickyColumn?.width || 0)
$visibleColumns.forEach(col => { $visibleColumns.forEach(col => {
width += col.width width += col.width
}) })
@ -45,7 +46,8 @@ export const createMaxScrollStores = context => {
) )
const screenWidth = derived( const screenWidth = derived(
[width, stickyColumn], [width, stickyColumn],
([$width, $stickyColumn]) => $width + 40 + ($stickyColumn?.width || 0), ([$width, $stickyColumn]) =>
$width + gutterWidth + ($stickyColumn?.width || 0),
0 0
) )
const maxScrollLeft = derived( const maxScrollLeft = derived(

View File

@ -6,6 +6,7 @@ export const createUIStores = context => {
const selectedRows = writable({}) const selectedRows = writable({})
const hoveredRowId = writable(null) const hoveredRowId = writable(null)
const selectedCellAPI = writable(null) const selectedCellAPI = writable(null)
const sidePanelRowId = writable(null)
// Derive the row that contains the selected cell. // Derive the row that contains the selected cell.
const selectedCellRow = derived( const selectedCellRow = derived(
@ -92,6 +93,7 @@ export const createUIStores = context => {
hoveredRowId, hoveredRowId,
selectedCellRow, selectedCellRow,
selectedCellAPI, selectedCellAPI,
sidePanelRowId,
ui: { ui: {
actions: { actions: {
blur, blur,