Add popovers to sheet column headers, improve mouse UX
This commit is contained in:
parent
36e8664605
commit
b93f575bca
|
@ -19,6 +19,7 @@
|
||||||
export let dismissible = true
|
export let dismissible = true
|
||||||
export let offset = 5
|
export let offset = 5
|
||||||
export let customHeight
|
export let customHeight
|
||||||
|
export let animate = true
|
||||||
|
|
||||||
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
|
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@
|
||||||
class="spectrum-Popover is-open"
|
class="spectrum-Popover is-open"
|
||||||
role="presentation"
|
role="presentation"
|
||||||
style="height: {customHeight}"
|
style="height: {customHeight}"
|
||||||
transition:fly|local={{ y: -20, duration: 200 }}
|
transition:fly|local={{ y: -20, duration: animate ? 200 : 0 }}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -228,5 +228,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
const {
|
const { columns, rand, scroll, visibleColumns, stickyColumn } =
|
||||||
visibleRows,
|
getContext("sheet")
|
||||||
columns,
|
|
||||||
rand,
|
|
||||||
scroll,
|
|
||||||
visibleColumns,
|
|
||||||
cellHeight,
|
|
||||||
stickyColumn,
|
|
||||||
} = getContext("sheet")
|
|
||||||
const MinColumnWidth = 100
|
const MinColumnWidth = 100
|
||||||
|
|
||||||
let initialMouseX = null
|
let initialMouseX = null
|
||||||
|
@ -22,8 +15,6 @@
|
||||||
$: scrollLeft = $scroll.left
|
$: scrollLeft = $scroll.left
|
||||||
$: cutoff = scrollLeft + 40 + ($columns[0]?.width || 0)
|
$: cutoff = scrollLeft + 40 + ($columns[0]?.width || 0)
|
||||||
$: offset = 40 + ($stickyColumn?.width || 0)
|
$: offset = 40 + ($stickyColumn?.width || 0)
|
||||||
$: rowCount = $visibleRows.length
|
|
||||||
$: contentHeight = (rowCount + 2) * cellHeight
|
|
||||||
|
|
||||||
const startResizing = (idx, e) => {
|
const startResizing = (idx, e) => {
|
||||||
// Prevent propagation to stop reordering triggering
|
// Prevent propagation to stop reordering triggering
|
||||||
|
@ -78,9 +69,9 @@
|
||||||
document.getElementById(`sheet-${rand}`).classList.remove("is-resizing")
|
document.getElementById(`sheet-${rand}`).classList.remove("is-resizing")
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyle = (col, offset, scrollLeft, contentHeight) => {
|
const getStyle = (col, offset, scrollLeft) => {
|
||||||
const left = offset + col.left + col.width - scrollLeft
|
const left = offset + col.left + col.width - scrollLeft
|
||||||
return `--left:${left}px; --content-height:${contentHeight}px;`
|
return `--left:${left}px;`
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -89,8 +80,7 @@
|
||||||
class="resize-slider sticky"
|
class="resize-slider sticky"
|
||||||
class:visible={columnIdx === "sticky"}
|
class:visible={columnIdx === "sticky"}
|
||||||
on:mousedown={e => startResizing("sticky", e)}
|
on:mousedown={e => startResizing("sticky", e)}
|
||||||
style="--left:{40 +
|
style="--left:{40 + $stickyColumn.width}px;"
|
||||||
$stickyColumn.width}px; --content-height:{contentHeight}px;"
|
|
||||||
>
|
>
|
||||||
<div class="resize-indicator" />
|
<div class="resize-indicator" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -100,7 +90,7 @@
|
||||||
class="resize-slider"
|
class="resize-slider"
|
||||||
class:visible={columnIdx === col.idx}
|
class:visible={columnIdx === col.idx}
|
||||||
on:mousedown={e => startResizing(col.idx, e)}
|
on:mousedown={e => startResizing(col.idx, e)}
|
||||||
style={getStyle(col, offset, scrollLeft, contentHeight)}
|
style={getStyle(col, offset, scrollLeft)}
|
||||||
>
|
>
|
||||||
<div class="resize-indicator" />
|
<div class="resize-indicator" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -114,7 +104,7 @@
|
||||||
height: var(--cell-height);
|
height: var(--cell-height);
|
||||||
left: var(--left);
|
left: var(--left);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
padding: 0 16px;
|
padding: 0 8px;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +112,6 @@
|
||||||
.resize-slider.visible {
|
.resize-slider.visible {
|
||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
height: min(var(--content-height), 100%);
|
|
||||||
}
|
}
|
||||||
.resize-slider.sticky {
|
.resize-slider.sticky {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import SheetCell from "./cells/SheetCell.svelte"
|
import SheetCell from "./cells/SheetCell.svelte"
|
||||||
import { getCellRenderer } from "./renderers"
|
import { getCellRenderer } from "./renderers"
|
||||||
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
||||||
|
import HeaderCell from "./cells/HeaderCell.svelte"
|
||||||
|
|
||||||
const {
|
const {
|
||||||
rows,
|
rows,
|
||||||
|
@ -67,6 +68,7 @@
|
||||||
<!-- Field headers -->
|
<!-- Field headers -->
|
||||||
<SheetCell
|
<SheetCell
|
||||||
header
|
header
|
||||||
|
foo
|
||||||
label
|
label
|
||||||
width="40"
|
width="40"
|
||||||
on:click={$config.allowSelectRows && selectAll}
|
on:click={$config.allowSelectRows && selectAll}
|
||||||
|
@ -77,21 +79,7 @@
|
||||||
</SheetCell>
|
</SheetCell>
|
||||||
|
|
||||||
{#if $stickyColumn}
|
{#if $stickyColumn}
|
||||||
<SheetCell
|
<HeaderCell column={$stickyColumn} />
|
||||||
header
|
|
||||||
sticky
|
|
||||||
width={$stickyColumn.width}
|
|
||||||
reorderTarget={$reorder.targetColumn === $stickyColumn.name}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
size="S"
|
|
||||||
name={getIconForField($stickyColumn)}
|
|
||||||
color="var(--spectrum-global-color-gray-600)"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
{$stickyColumn.name}
|
|
||||||
</span>
|
|
||||||
</SheetCell>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,92 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import SheetCell from "./SheetCell.svelte"
|
import SheetCell from "./SheetCell.svelte"
|
||||||
import { Icon, Popover } from "@budibase/bbui"
|
import { Icon, Popover, Menu, MenuItem } from "@budibase/bbui"
|
||||||
import { getIconForField } from "../utils"
|
import { getIconForField } from "../utils"
|
||||||
|
|
||||||
export let column
|
export let column
|
||||||
|
|
||||||
const { reorder } = getContext("sheet")
|
const { reorder, isReordering, rand } = getContext("sheet")
|
||||||
|
|
||||||
let popover
|
let timeout
|
||||||
let anchor
|
let anchor
|
||||||
|
let open = false
|
||||||
|
let isClick = true
|
||||||
|
|
||||||
const openPopover = () => {
|
const startReordering = e => {
|
||||||
console.log("open")
|
isClick = true
|
||||||
popover.show()
|
timeout = setTimeout(() => {
|
||||||
|
isClick = false
|
||||||
|
reorder.actions.startReordering(column.name, e)
|
||||||
|
}, 250)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopReordering = () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
if (isClick) {
|
||||||
|
stopReordering()
|
||||||
|
open = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="header-cell" bind:this={anchor}>
|
<div
|
||||||
|
class="header-cell"
|
||||||
|
class:open
|
||||||
|
style="flex: 0 0 {column.width}px;"
|
||||||
|
bind:this={anchor}
|
||||||
|
class:disabled={$isReordering}
|
||||||
|
>
|
||||||
<SheetCell
|
<SheetCell
|
||||||
reorderSource={$reorder.sourceColumn === column.name}
|
reorderSource={$reorder.sourceColumn === column.name}
|
||||||
reorderTarget={$reorder.targetColumn === column.name}
|
reorderTarget={$reorder.targetColumn === column.name}
|
||||||
on:mousedown={e => reorder.actions.startReordering(column.name, e)}
|
on:mousedown={startReordering}
|
||||||
on:click={openPopover}
|
on:mouseup={stopReordering}
|
||||||
|
on:click={onClick}
|
||||||
width={column.width}
|
width={column.width}
|
||||||
left={column.left}
|
left={column.left}
|
||||||
>
|
>
|
||||||
<div class="content">
|
<Icon
|
||||||
<Icon
|
size="S"
|
||||||
size="S"
|
name={getIconForField(column)}
|
||||||
name={getIconForField(column)}
|
color="var(--spectrum-global-color-gray-600)"
|
||||||
color="var(--spectrum-global-color-gray-600)"
|
/>
|
||||||
/>
|
<div class="name">
|
||||||
<div class="name">
|
{column.name}
|
||||||
{column.name} asdasdasd asdasdas asdasdasd
|
</div>
|
||||||
</div>
|
<div class="more">
|
||||||
<div class="more">
|
<Icon size="S" name="MoreVertical" />
|
||||||
<Icon size="S" name="MoreVertical" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</SheetCell>
|
</SheetCell>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Popover bind:this={popover} {anchor} align="left"
|
<Popover
|
||||||
>asdsad asdasd asdasd asasa</Popover
|
bind:open
|
||||||
|
{anchor}
|
||||||
|
align="left"
|
||||||
|
offset={0}
|
||||||
|
popoverTarget={document.getElementById(`sheet-${rand}`)}
|
||||||
|
animate={false}
|
||||||
>
|
>
|
||||||
|
<Menu>
|
||||||
|
<MenuItem icon="Edit">Edit column</MenuItem>
|
||||||
|
<MenuItem icon="SortOrderUp">Sort ascending</MenuItem>
|
||||||
|
<MenuItem icon="SortOrderDown">Sort descending</MenuItem>
|
||||||
|
<MenuItem icon="ArrowLeft">Move left</MenuItem>
|
||||||
|
<MenuItem icon="ArrowRight">Move right</MenuItem>
|
||||||
|
<MenuItem icon="Delete">Delete</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.header-cell {
|
.header-cell {
|
||||||
display: contents;
|
display: flex;
|
||||||
}
|
}
|
||||||
.header-cell:hover :global(.cell) {
|
.header-cell:not(.disabled):hover :global(.cell),
|
||||||
|
.header-cell:not(.disabled).open :global(.cell) {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: var(--spectrum-global-color-gray-200);
|
background: var(--spectrum-global-color-gray-200);
|
||||||
}
|
}
|
||||||
|
@ -72,7 +108,8 @@
|
||||||
.more {
|
.more {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.header-cell:hover .more {
|
.header-cell:not(.disabled):hover .more,
|
||||||
|
.header-cell:not(.disabled).open .more {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
export let center = false
|
export let center = false
|
||||||
export let selectedUser = null
|
export let selectedUser = null
|
||||||
export let rowIdx
|
export let rowIdx
|
||||||
|
export let foo
|
||||||
|
|
||||||
$: style = getStyle(width, selectedUser)
|
$: style = getStyle(width, selectedUser)
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="cell"
|
class="cell"
|
||||||
|
class:foo
|
||||||
class:label
|
class:label
|
||||||
class:row-selected={rowSelected}
|
class:row-selected={rowSelected}
|
||||||
class:row-hovered={rowHovered}
|
class:row-hovered={rowHovered}
|
||||||
|
@ -34,8 +36,9 @@
|
||||||
class:reorder-target={reorderTarget}
|
class:reorder-target={reorderTarget}
|
||||||
class:center
|
class:center
|
||||||
on:focus
|
on:focus
|
||||||
on:click
|
|
||||||
on:mousedown
|
on:mousedown
|
||||||
|
on:mouseup
|
||||||
|
on:click
|
||||||
{style}
|
{style}
|
||||||
data-row={rowIdx}
|
data-row={rowIdx}
|
||||||
>
|
>
|
||||||
|
@ -113,6 +116,9 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.cell.foo {
|
||||||
|
background: var(--spectrum-global-color-gray-100);
|
||||||
|
}
|
||||||
|
|
||||||
/* Other user email */
|
/* Other user email */
|
||||||
.user {
|
.user {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { get, writable } from "svelte/store"
|
import { get, writable, derived } from "svelte/store"
|
||||||
|
|
||||||
export const createReorderStores = context => {
|
export const createReorderStores = context => {
|
||||||
const { columns, rand, scroll, bounds, stickyColumn } = context
|
const { columns, rand, scroll, bounds, stickyColumn } = context
|
||||||
|
@ -7,8 +7,11 @@ export const createReorderStores = context => {
|
||||||
targetColumn: null,
|
targetColumn: null,
|
||||||
breakpoints: [],
|
breakpoints: [],
|
||||||
initialMouseX: null,
|
initialMouseX: null,
|
||||||
|
scrollLeft: 0,
|
||||||
|
sheetLeft: 0,
|
||||||
}
|
}
|
||||||
const reorder = writable(reorderInitialState)
|
const reorder = writable(reorderInitialState)
|
||||||
|
const isReordering = derived(reorder, $reorder => !!$reorder.sourceColumn)
|
||||||
|
|
||||||
// Callback when dragging on a colum header and starting reordering
|
// Callback when dragging on a colum header and starting reordering
|
||||||
const startReordering = (column, e) => {
|
const startReordering = (column, e) => {
|
||||||
|
@ -115,5 +118,6 @@ export const createReorderStores = context => {
|
||||||
stopReordering,
|
stopReordering,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
isReordering,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Koa from "koa"
|
||||||
import Cookies from "cookies"
|
import Cookies from "cookies"
|
||||||
import { userAgent } from "koa-useragent"
|
import { userAgent } from "koa-useragent"
|
||||||
import { auth } from "@budibase/backend-core"
|
import { auth } from "@budibase/backend-core"
|
||||||
|
import currentApp from "../middleware/currentapp"
|
||||||
|
|
||||||
export default class Socket {
|
export default class Socket {
|
||||||
io: Server
|
io: Server
|
||||||
|
@ -25,6 +26,7 @@ export default class Socket {
|
||||||
const middlewares = [
|
const middlewares = [
|
||||||
userAgent,
|
userAgent,
|
||||||
authenticate,
|
authenticate,
|
||||||
|
// currentApp,
|
||||||
...(additionalMiddlewares || []),
|
...(additionalMiddlewares || []),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue