Initial work on nested nav links
This commit is contained in:
parent
cecd5a1908
commit
9fe027b3db
|
@ -14,7 +14,6 @@
|
|||
export let key
|
||||
export let nested
|
||||
export let max
|
||||
export let context
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
<div class="right-content">
|
||||
<svelte:component
|
||||
this={listType}
|
||||
anchor={anchors[draggableItem.item._id]}
|
||||
anchor={anchors[draggableItem.id]}
|
||||
item={draggableItem.item}
|
||||
{...listTypeProps}
|
||||
on:change={onItemChanged}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<script>
|
||||
import { Icon, Popover, Layout } from "@budibase/bbui"
|
||||
import { createEventDispatcher, getContext } from "svelte"
|
||||
|
||||
export let anchor
|
||||
export let navItem
|
||||
|
||||
const draggable = getContext("draggable")
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let popover
|
||||
let drawers = []
|
||||
let open = false
|
||||
|
||||
$: console.log(anchor)
|
||||
|
||||
// Auto hide the component when another item is selected
|
||||
$: if (open && $draggable.selected !== navItem.id) {
|
||||
popover.hide()
|
||||
}
|
||||
|
||||
// Open automatically if the component is marked as selected
|
||||
$: if (!open && $draggable.selected === navItem.id && popover) {
|
||||
popover.show()
|
||||
open = true
|
||||
}
|
||||
|
||||
const updateNavItem = async (setting, value) => {
|
||||
dispatch("change", {
|
||||
...navItem,
|
||||
[setting]: value,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<Icon
|
||||
name="Settings"
|
||||
hoverable
|
||||
size="S"
|
||||
on:click={() => {
|
||||
if (!open) {
|
||||
popover.show()
|
||||
open = true
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Popover
|
||||
bind:this={popover}
|
||||
on:open={() => {
|
||||
drawers = []
|
||||
$draggable.actions.select(navItem.id)
|
||||
}}
|
||||
on:close={() => {
|
||||
open = false
|
||||
if ($draggable.selected === navItem.id) {
|
||||
$draggable.actions.select()
|
||||
}
|
||||
}}
|
||||
{anchor}
|
||||
align="left-outside"
|
||||
showPopover={drawers.length === 0}
|
||||
clickOutsideOverride={drawers.length > 0}
|
||||
maxHeight={600}
|
||||
offset={18}
|
||||
>
|
||||
<span class="popover-wrap">
|
||||
<Layout noPadding />
|
||||
</span>
|
||||
</Popover>
|
||||
|
||||
<style>
|
||||
.popover-wrap {
|
||||
background-color: var(--spectrum-alias-background-color-primary);
|
||||
}
|
||||
</style>
|
|
@ -1,30 +0,0 @@
|
|||
<script>
|
||||
import { Button, Drawer } from "@budibase/bbui"
|
||||
import NavigationLinksDrawer from "./LinksDrawer.svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { navigationStore } from "stores/builder"
|
||||
|
||||
let drawer
|
||||
let links
|
||||
|
||||
const openDrawer = () => {
|
||||
links = cloneDeep($navigationStore.links || [])
|
||||
drawer.show()
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
let navigation = $navigationStore
|
||||
navigation.links = links
|
||||
await navigationStore.save(navigation)
|
||||
drawer.hide()
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button cta on:click={openDrawer}>Configure Links</Button>
|
||||
<Drawer bind:this={drawer} title={"Navigation Links"}>
|
||||
<svelte:fragment slot="description">
|
||||
Configure the links in your navigation bar.
|
||||
</svelte:fragment>
|
||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||
<NavigationLinksDrawer slot="body" bind:links />
|
||||
</Drawer>
|
|
@ -0,0 +1,51 @@
|
|||
<script>
|
||||
import EditNavItemPopover from "./EditNavItemPopover.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
|
||||
export let item
|
||||
export let removeNavItem
|
||||
export let anchor
|
||||
</script>
|
||||
|
||||
<div class="list-item-body">
|
||||
<div class="list-item-left">
|
||||
<EditNavItemPopover {anchor} navItem={item} on:change />
|
||||
<div class="field-label">{item.text}</div>
|
||||
</div>
|
||||
<div class="list-item-right">
|
||||
<Icon
|
||||
size="S"
|
||||
name="Close"
|
||||
hoverable
|
||||
on:click={e => {
|
||||
e.stopPropagation()
|
||||
removeNavItem(item.id)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.field-label {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.list-item-body,
|
||||
.list-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-m);
|
||||
min-width: 0;
|
||||
}
|
||||
.list-item-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.list-item-right :global(div.spectrum-Switch) {
|
||||
margin: 0px;
|
||||
}
|
||||
.list-item-body {
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,113 @@
|
|||
<script>
|
||||
import { navigationStore } from "stores/builder"
|
||||
import DraggableList from "components/design/settings/controls/DraggableList/DraggableList.svelte"
|
||||
import NavItem from "./NavItem.svelte"
|
||||
import { generate } from "shortid"
|
||||
import { getSequentialName } from "helpers/duplicate"
|
||||
import { Constants } from "@budibase/frontend-core"
|
||||
|
||||
$: navItems = enrichNavItems($navigationStore.links)
|
||||
$: navItemProps = {
|
||||
removeNavItem,
|
||||
}
|
||||
|
||||
const enrichNavItems = links => {
|
||||
return (links || []).map(link => ({
|
||||
...link,
|
||||
id: link.id || generate(),
|
||||
}))
|
||||
}
|
||||
|
||||
const save = async links => {
|
||||
await navigationStore.save({ ...$navigationStore, links })
|
||||
}
|
||||
|
||||
const handleNavItemUpdate = async e => {
|
||||
const newNavItem = e.detail
|
||||
const newLinks = [...navItems]
|
||||
const idx = newLinks.findIndex(link => {
|
||||
return link.id === newNavItem?.id
|
||||
})
|
||||
if (idx === -1) {
|
||||
newLinks.push(newNavItem)
|
||||
} else {
|
||||
newLinks[idx] = newNavItem
|
||||
}
|
||||
await save(newLinks)
|
||||
}
|
||||
|
||||
const handleListUpdate = async e => {
|
||||
await save([...e.detail])
|
||||
}
|
||||
|
||||
const addLink = async () => {
|
||||
await save([
|
||||
...navItems,
|
||||
{
|
||||
id: generate(),
|
||||
text: getSequentialName(navItems, "Nav Item ", x => x.text),
|
||||
url: "",
|
||||
roleId: Constants.Roles.BASIC,
|
||||
type: "link",
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
const removeNavItem = async id => {
|
||||
await save(navItems.filter(navItem => navItem.id !== id))
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="link-configuration">
|
||||
{#if navItems.length}
|
||||
<DraggableList
|
||||
on:change={handleListUpdate}
|
||||
on:itemChange={handleNavItemUpdate}
|
||||
items={navItems}
|
||||
listItemKey="id"
|
||||
listType={NavItem}
|
||||
listTypeProps={navItemProps}
|
||||
draggable={navItems.length > 1}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div class="list-footer" on:click={addLink} class:empty={!navItems.length}>
|
||||
<div class="add-button">Add nav item</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.list-footer {
|
||||
width: 100%;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
background-color: var(
|
||||
--spectrum-table-background-color,
|
||||
var(--spectrum-global-color-gray-50)
|
||||
);
|
||||
transition: background-color ease-in-out 130ms;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--spectrum-alias-border-color-mid);
|
||||
border-top: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.list-footer.empty {
|
||||
border-top: 1px solid var(--spectrum-alias-border-color-mid);
|
||||
}
|
||||
.list-footer.empty {
|
||||
border-radius: 4px;
|
||||
}
|
||||
.list-footer:hover {
|
||||
background-color: var(
|
||||
--spectrum-table-row-background-color-hover,
|
||||
var(--spectrum-alias-highlight-hover)
|
||||
);
|
||||
}
|
||||
|
||||
.add-button {
|
||||
margin: var(--spacing-s);
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import LinksEditor from "./LinksEditor.svelte"
|
||||
import NavItemConfiguration from "./NavItemConfiguration.svelte"
|
||||
import { get } from "svelte/store"
|
||||
import Panel from "components/design/Panel.svelte"
|
||||
import {
|
||||
|
@ -75,7 +75,7 @@
|
|||
|
||||
{#if $selectedScreen?.showNavigation}
|
||||
<DetailSummary name="Customize" initiallyShow collapsible={false}>
|
||||
<LinksEditor />
|
||||
<NavItemConfiguration />
|
||||
<div class="settings">
|
||||
<PropertyControl
|
||||
label="Position"
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
|
||||
const getValidLinks = (allLinks, userRoleHierarchy) => {
|
||||
// Strip links missing required info
|
||||
let validLinks = (allLinks || []).filter(link => link.text && link.url)
|
||||
let validLinks = (allLinks || []).filter(link => link.text)
|
||||
// Filter to only links allowed by the current role
|
||||
return validLinks.filter(link => {
|
||||
const role = link.roleId || Constants.Roles.BASIC
|
||||
|
|
Loading…
Reference in New Issue