forked from tsai/budibase
3 changed files with 254 additions and 1 deletions
@ -0,0 +1,139 @@ |
|||||
|
<script> |
||||
|
import { store } from "builderStore" |
||||
|
import ComponentDropdownMenu from "../ComponentDropdownMenu.svelte" |
||||
|
import { DropEffect, DropPosition } from "./dragDropStore" |
||||
|
import NavItem from "components/common/NavItem.svelte" |
||||
|
import { TreeView, TreeItem as Item} from '@budibase/bbui' |
||||
|
|
||||
|
export let components = [] |
||||
|
export let currentComponent |
||||
|
export let dragDropStore |
||||
|
|
||||
|
const isScreenslot = name => name?.endsWith("screenslot") |
||||
|
|
||||
|
const selectComponent = component => { |
||||
|
store.actions.components.select(component) |
||||
|
} |
||||
|
|
||||
|
const dragstart = component => e => { |
||||
|
e.dataTransfer.dropEffect = DropEffect.MOVE |
||||
|
dragDropStore.actions.dragstart(component) |
||||
|
} |
||||
|
|
||||
|
const dragover = (component, index) => e => { |
||||
|
const definition = store.actions.components.getDefinition( |
||||
|
component._component |
||||
|
) |
||||
|
const canHaveChildrenButIsEmpty = |
||||
|
definition?.hasChildren && !component._children?.length |
||||
|
|
||||
|
e.dataTransfer.dropEffect = DropEffect.COPY |
||||
|
|
||||
|
// how far down the mouse pointer is on the drop target |
||||
|
const mousePosition = e.offsetY / e.currentTarget.offsetHeight |
||||
|
|
||||
|
dragDropStore.actions.dragover({ |
||||
|
component, |
||||
|
index, |
||||
|
canHaveChildrenButIsEmpty, |
||||
|
mousePosition, |
||||
|
}) |
||||
|
|
||||
|
return false |
||||
|
} |
||||
|
</script> |
||||
|
{#each components as component, index (component._id)} |
||||
|
{#if $dragDropStore?.targetComponent === component && $dragDropStore.dropPosition === DropPosition.ABOVE} |
||||
|
<div |
||||
|
on:drop={dragDropStore.actions.drop} |
||||
|
ondragover="return false" |
||||
|
ondragenter="return false" |
||||
|
class="drop-item" /> |
||||
|
{/if} |
||||
|
<Item |
||||
|
draggable |
||||
|
on:dragend={dragDropStore.actions.reset} |
||||
|
on:dragstart={dragstart(component)} |
||||
|
on:dragover={dragover(component, index)} |
||||
|
on:drop={dragDropStore.actions.drop} |
||||
|
on:click={() => selectComponent(component)} |
||||
|
title={isScreenslot(component._component) ? 'Screenslot' : component._instanceName} |
||||
|
open |
||||
|
selected={$store.selectedComponentId === component._id}> |
||||
|
{#if component._children} |
||||
|
<svelte:self |
||||
|
components={component._children} |
||||
|
{currentComponent} |
||||
|
{dragDropStore} |
||||
|
/> |
||||
|
{/if} |
||||
|
</Item> |
||||
|
{#if $dragDropStore?.targetComponent === component && ($dragDropStore.dropPosition === DropPosition.INSIDE || $dragDropStore.dropPosition === DropPosition.BELOW)} |
||||
|
<div |
||||
|
on:drop={dragDropStore.actions.drop} |
||||
|
ondragover="return false" |
||||
|
ondragenter="return false" |
||||
|
class="drop-item"/> |
||||
|
{/if} |
||||
|
{/each} |
||||
|
|
||||
|
<!-- <ul> |
||||
|
{#each components as component, index (component._id)} |
||||
|
<li on:click|stopPropagation={() => selectComponent(component)}> |
||||
|
{#if $dragDropStore?.targetComponent === component && $dragDropStore.dropPosition === DropPosition.ABOVE} |
||||
|
<div |
||||
|
on:drop={dragDropStore.actions.drop} |
||||
|
ondragover="return false" |
||||
|
ondragenter="return false" |
||||
|
class="drop-item" |
||||
|
style="margin-left: {(level + 1) * 16}px" /> |
||||
|
{/if} |
||||
|
|
||||
|
<NavItem |
||||
|
draggable |
||||
|
on:dragend={dragDropStore.actions.reset} |
||||
|
on:dragstart={dragstart(component)} |
||||
|
on:dragover={dragover(component, index)} |
||||
|
on:drop={dragDropStore.actions.drop} |
||||
|
text={isScreenslot(component._component) ? 'Screenslot' : component._instanceName} |
||||
|
withArrow |
||||
|
indentLevel={level + 1} |
||||
|
selected={$store.selectedComponentId === component._id}> |
||||
|
<ComponentDropdownMenu {component} /> |
||||
|
</NavItem> |
||||
|
|
||||
|
{#if component._children} |
||||
|
<svelte:self |
||||
|
components={component._children} |
||||
|
{currentComponent} |
||||
|
{onSelect} |
||||
|
{dragDropStore} |
||||
|
level={level + 1} /> |
||||
|
{/if} |
||||
|
|
||||
|
{#if $dragDropStore?.targetComponent === component && ($dragDropStore.dropPosition === DropPosition.INSIDE || $dragDropStore.dropPosition === DropPosition.BELOW)} |
||||
|
<div |
||||
|
on:drop={dragDropStore.actions.drop} |
||||
|
ondragover="return false" |
||||
|
ondragenter="return false" |
||||
|
class="drop-item" |
||||
|
style="margin-left: {(level + ($dragDropStore.dropPosition === DropPosition.INSIDE ? 3 : 1)) * 16}px" /> |
||||
|
{/if} |
||||
|
</li> |
||||
|
{/each} |
||||
|
</ul> --> |
||||
|
|
||||
|
<style> |
||||
|
ul { |
||||
|
list-style: none; |
||||
|
padding-left: 0; |
||||
|
margin: 0; |
||||
|
} |
||||
|
|
||||
|
.drop-item { |
||||
|
border-radius: var(--border-radius-m); |
||||
|
height: 32px; |
||||
|
background: var(--grey-3); |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
@ -0,0 +1,114 @@ |
|||||
|
<script> |
||||
|
import { TreeItem as Item} from '@budibase/bbui' |
||||
|
import { |
||||
|
store, |
||||
|
selectedComponent, |
||||
|
currentAsset, |
||||
|
screenSearchString, |
||||
|
} from "builderStore" |
||||
|
import instantiateStore from "./dragDropStore" |
||||
|
import ComponentTree from "./NewComponentTree.svelte" |
||||
|
import { get } from "svelte/store" |
||||
|
|
||||
|
const ROUTE_NAME_MAP = { |
||||
|
"/": { |
||||
|
BASIC: "Home", |
||||
|
PUBLIC: "Login", |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const dragDropStore = instantiateStore() |
||||
|
|
||||
|
export let route |
||||
|
export let path |
||||
|
|
||||
|
let routeManuallyOpened = false |
||||
|
$: selectedScreen = $currentAsset |
||||
|
$: allScreens = getAllScreens(route) |
||||
|
$: filteredScreens = getFilteredScreens(allScreens, $screenSearchString) |
||||
|
$: hasSearchMatch = $screenSearchString && filteredScreens.length > 0 |
||||
|
$: noSearchMatch = $screenSearchString && !filteredScreens.length |
||||
|
$: routeSelected = |
||||
|
route.subpaths[selectedScreen?.routing?.route] !== undefined |
||||
|
$: routeOpened = routeManuallyOpened || routeSelected || hasSearchMatch |
||||
|
|
||||
|
const changeScreen = screenId => { |
||||
|
store.actions.screens.select(screenId) |
||||
|
} |
||||
|
|
||||
|
const getAllScreens = route => { |
||||
|
let screens = [] |
||||
|
Object.entries(route.subpaths).forEach(([route, subpath]) => { |
||||
|
Object.entries(subpath.screens).forEach(([role, id]) => { |
||||
|
screens.push({ id, route, role }) |
||||
|
}) |
||||
|
}) |
||||
|
return screens |
||||
|
} |
||||
|
|
||||
|
const getFilteredScreens = (screens, searchString) => { |
||||
|
return screens.filter( |
||||
|
screen => !searchString || screen.route.includes(searchString) |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
const toggleManuallyOpened = () => { |
||||
|
if (get(screenSearchString)) { |
||||
|
return |
||||
|
} |
||||
|
routeManuallyOpened = !routeManuallyOpened |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
{#if !noSearchMatch} |
||||
|
<Item icon="Folder" title={path} open={routeOpened}> |
||||
|
{#if routeOpened} |
||||
|
{#each filteredScreens as screen (screen.id)} |
||||
|
<Item |
||||
|
icon="ModernGridView" |
||||
|
selected={$store.selectedScreenId === screen.id} |
||||
|
open={$store.selectedScreenId === screen.id} |
||||
|
on:click={toggleManuallyOpened} |
||||
|
title={ROUTE_NAME_MAP[screen.route]?.[screen.role] || screen.route} |
||||
|
on:click={() => changeScreen(screen.id)}> |
||||
|
{#if selectedScreen?._id === screen.id} |
||||
|
<ComponentTree |
||||
|
components={selectedScreen.props._children} |
||||
|
currentComponent={$selectedComponent} |
||||
|
{dragDropStore} /> |
||||
|
{/if} |
||||
|
</Item> |
||||
|
{/each} |
||||
|
{/if} |
||||
|
</Item> |
||||
|
|
||||
|
<!-- <NavItem |
||||
|
icon="ri-folder-line" |
||||
|
text={path} |
||||
|
on:click={toggleManuallyOpened} |
||||
|
opened={routeOpened} |
||||
|
{border} |
||||
|
withArrow={route.subpaths} /> |
||||
|
|
||||
|
{#if routeOpened} |
||||
|
{#each filteredScreens as screen (screen.id)} |
||||
|
<NavItem |
||||
|
icon="ri-artboard-2-line" |
||||
|
indentLevel={indent || 1} |
||||
|
selected={$store.selectedScreenId === screen.id} |
||||
|
opened={$store.selectedScreenId === screen.id} |
||||
|
text={ROUTE_NAME_MAP[screen.route]?.[screen.role] || screen.route} |
||||
|
withArrow={route.subpaths} |
||||
|
on:click={() => changeScreen(screen.id)}> |
||||
|
<ScreenDropdownMenu screenId={screen.id} /> |
||||
|
</NavItem> |
||||
|
{#if selectedScreen?._id === screen.id} |
||||
|
<ComponentTree |
||||
|
level={1} |
||||
|
components={selectedScreen.props._children} |
||||
|
currentComponent={$selectedComponent} |
||||
|
{dragDropStore} /> |
||||
|
{/if} |
||||
|
{/each} |
||||
|
{/if} --> |
||||
|
{/if} |
||||
Loading…
Reference in new issue