From d377186f0da38460b3d8bcd709f6299d22b19d47 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 16 Aug 2024 18:43:48 +0100 Subject: [PATCH] Add double layer context menu for overflow views --- .../bbui/src/ActionButton/ActionButton.svelte | 1 + .../bbui/src/ActionMenu/ActionMenu.svelte | 41 ++++++- .../bbui/src/Actions/position_dropdown.js | 10 +- packages/bbui/src/Menu/Item.svelte | 5 +- packages/bbui/src/Popover/Popover.svelte | 29 ++++- .../[tableId]/_components/ViewNavBar.svelte | 112 +++++++++++++----- 6 files changed, 156 insertions(+), 42 deletions(-) diff --git a/packages/bbui/src/ActionButton/ActionButton.svelte b/packages/bbui/src/ActionButton/ActionButton.svelte index d3cec0f307..7019ad7d2c 100644 --- a/packages/bbui/src/ActionButton/ActionButton.svelte +++ b/packages/bbui/src/ActionButton/ActionButton.svelte @@ -115,6 +115,7 @@ } .spectrum-ActionButton--quiet.is-selected { color: var(--spectrum-global-color-gray-900); + background: var(--spectrum-global-color-gray-300); } .noPadding { padding: 0; diff --git a/packages/bbui/src/ActionMenu/ActionMenu.svelte b/packages/bbui/src/ActionMenu/ActionMenu.svelte index 75ddd679da..e3de70e3ee 100644 --- a/packages/bbui/src/ActionMenu/ActionMenu.svelte +++ b/packages/bbui/src/ActionMenu/ActionMenu.svelte @@ -1,14 +1,20 @@ -
+
diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 21635592d2..c3675cfbe6 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -151,9 +151,9 @@ export default function positionDropdown(element, opts) { // Determine X strategy if (align === "right") { applyXStrategy(Strategies.EndToEnd) - } else if (align === "right-outside") { + } else if (align === "right-outside" || align === "right-context-menu") { applyXStrategy(Strategies.StartToEnd) - } else if (align === "left-outside") { + } else if (align === "left-outside" || align === "left-context-menu") { applyXStrategy(Strategies.EndToStart) } else if (align === "center") { applyXStrategy(Strategies.MidPoint) @@ -164,6 +164,12 @@ export default function positionDropdown(element, opts) { // Determine Y strategy if (align === "right-outside" || align === "left-outside") { applyYStrategy(Strategies.MidPoint) + } else if ( + align === "right-context-menu" || + align === "left-context-menu" + ) { + applyYStrategy(Strategies.StartToStart) + styles.top -= 4 // Manual adjustment for action menu padding } else { applyYStrategy(Strategies.StartToEnd) } diff --git a/packages/bbui/src/Menu/Item.svelte b/packages/bbui/src/Menu/Item.svelte index 758b819a62..5e5f6d840c 100644 --- a/packages/bbui/src/Menu/Item.svelte +++ b/packages/bbui/src/Menu/Item.svelte @@ -27,7 +27,7 @@ const onClick = () => { if (actionMenu && !noClose) { - actionMenu.hide() + actionMenu.hideAll() } dispatch("click") } @@ -47,8 +47,9 @@
{/if} - {#if keys?.length} + {#if keys?.length || $$slots.right}
+ {#each keys as key}
{#if key.startsWith("!")} diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte index aa811afe1e..696e246d28 100644 --- a/packages/bbui/src/Popover/Popover.svelte +++ b/packages/bbui/src/Popover/Popover.svelte @@ -1,7 +1,7 @@ {#if open} @@ -104,9 +122,13 @@ class="spectrum-Popover is-open" class:customZindex class:hidden={!showPopover} + class:blockPointerEvents role="presentation" style="height: {customHeight}; --customZindex: {customZindex};" - transition:fly|local={{ y: -20, duration: animate ? 260 : 0 }} + transition:fly|local={{ + y: -20, + duration: animate ? animationDuration : 0, + }} on:mouseenter on:mouseleave > @@ -122,6 +144,9 @@ overflow: auto; transition: opacity 260ms ease-out; } + .blockPointerEvents { + pointer-events: none; + } .hidden { opacity: 0; pointer-events: none; diff --git a/packages/builder/src/pages/builder/app/[application]/data/table/[tableId]/_components/ViewNavBar.svelte b/packages/builder/src/pages/builder/app/[application]/data/table/[tableId]/_components/ViewNavBar.svelte index 7cc125ae67..7f92e0c055 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/table/[tableId]/_components/ViewNavBar.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/table/[tableId]/_components/ViewNavBar.svelte @@ -6,7 +6,13 @@ contextMenuStore, } from "stores/builder" import IntegrationIcon from "components/backend/DatasourceNavigator/IntegrationIcon.svelte" - import { Icon, Button, Popover, ActionMenu, MenuItem } from "@budibase/bbui" + import { + Icon, + Button, + ActionButton, + ActionMenu, + MenuItem, + } from "@budibase/bbui" import { params, url } from "@roxi/routify" import EditViewModal from "./EditViewModal.svelte" import DeleteViewModal from "./DeleteViewModal.svelte" @@ -19,12 +25,13 @@ import { alphabetical } from "components/backend/TableNavigator/utils" import CreateViewModal from "./CreateViewModal.svelte" import { onDestroy } from "svelte" + import { derived } from "svelte/store" - let viewContainer + // View overflow let observer + let viewContainer let viewVisibiltyMap = {} - let overflowPopover - let anchor + let overflowMenu // Editing table let createViewModal @@ -46,8 +53,15 @@ .filter(x => x.version === 2) .slice() .sort(alphabetical) - $: setUpObserver(viewContainer, views) + $: setUpObserver(views) $: overflowedViews = views.filter(view => !viewVisibiltyMap[view.id]) + $: viewHidden = viewVisibiltyMap[activeId] === false + + const viewUrl = derived([url, params], ([$url, $params]) => viewId => { + return $url(`../${$params.tableId}/${encodeURIComponent(viewId)}`) + }) + + const tableUrl = derived(url, $url => tableId => $url(`../${tableId}`)) const openTableContextMenu = e => { if (!tableEditable) { @@ -114,11 +128,24 @@ ) } - const setUpObserver = (viewContainer, views) => { - if (!views.length || !viewContainer) { - observer?.disconnect() + const editOverflowView = async view => { + editableView = view + await tick() + editViewModal?.show() + } + + const deleteOverflowView = async view => { + editableView = view + await tick() + deleteViewModal?.show() + } + + const setUpObserver = async views => { + observer?.disconnect() + if (!views.length) { return } + await tick() observer = new IntersectionObserver( entries => { let updates = {} @@ -136,7 +163,9 @@ } ) for (let child of viewContainer.children) { - observer.observe(child) + if (child.dataset.id) { + observer.observe(child) + } } } @@ -152,7 +181,7 @@ size="24" /> {/if} {#if overflowedViews.length} - +
- + + {overflowedViews.length} more +
{#each overflowedViews as view} -
- - {view.name} +
+ + + {view.name} + + + +
+ + Select + + editOverflowView(view)}> + Edit - + deleteOverflowView(view)}> + Delete + + {/each} {/if} @@ -266,22 +310,23 @@ justify-content: flex-start; align-items: center; padding: 0 var(--spacing-xl); - gap: 8px; + gap: 12px; } .nav__views { - width: 0; - flex: 1 1 auto; + flex: 0 1 auto; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; overflow: hidden; gap: 8px; + margin-left: -4px; } /* Table and view items */ .nav-item { - padding: 6px 8px; + padding: 0 8px; + height: 32px; border-radius: 4px; display: flex; flex-direction: row; @@ -309,4 +354,9 @@ white-space: nowrap; overflow: hidden; } + + /* OVerflow items */ + .nav-overflow-item:not(.active) :global(> .spectrum-Menu-item > .icon) { + visibility: hidden; + }