2020-06-01 23:16:55 +02:00
|
|
|
<script>
|
2020-10-13 10:06:56 +02:00
|
|
|
import { goto } from "@sveltech/routify"
|
2020-06-01 13:15:44 +02:00
|
|
|
import { store } from "builderStore"
|
2020-08-13 15:02:15 +02:00
|
|
|
import { getComponentDefinition } from "builderStore/storeUtils"
|
2020-06-01 13:15:44 +02:00
|
|
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
|
|
|
import { last, cloneDeep } from "lodash/fp"
|
2020-10-13 10:06:56 +02:00
|
|
|
import { getParent, saveCurrentPreviewItem } from "builderStore/storeUtils"
|
2020-06-01 13:15:44 +02:00
|
|
|
import { uuid } from "builderStore/uuid"
|
2020-09-07 00:50:11 +02:00
|
|
|
import { DropdownMenu } from "@budibase/bbui"
|
2020-06-01 13:15:44 +02:00
|
|
|
|
|
|
|
export let component
|
|
|
|
|
|
|
|
let confirmDeleteDialog
|
2020-09-06 23:58:47 +02:00
|
|
|
let dropdown
|
2020-09-07 00:50:11 +02:00
|
|
|
let anchor
|
2020-09-06 23:58:47 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
$: noChildrenAllowed =
|
2020-08-12 17:28:19 +02:00
|
|
|
!component || !getComponentDefinition($store, component._component).children
|
2020-06-02 12:11:53 +02:00
|
|
|
$: noPaste = !$store.componentToPaste
|
2020-06-01 13:15:44 +02:00
|
|
|
|
|
|
|
const lastPartOfName = c => (c ? last(c._component.split("/")) : "")
|
|
|
|
|
|
|
|
const hideDropdown = () => {
|
|
|
|
dropdown.hide()
|
|
|
|
}
|
|
|
|
|
2020-10-13 10:06:56 +02:00
|
|
|
const selectComponent = component => {
|
|
|
|
store.selectComponent(component)
|
|
|
|
const path = store.getPathToComponent(component)
|
|
|
|
$goto(`./:page/:screen/${path}`)
|
|
|
|
}
|
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
const moveUpComponent = () => {
|
|
|
|
store.update(s => {
|
|
|
|
const parent = getParent(s.currentPreviewItem.props, component)
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
const currentIndex = parent._children.indexOf(component)
|
|
|
|
if (currentIndex === 0) return s
|
|
|
|
|
|
|
|
const newChildren = parent._children.filter(c => c !== component)
|
|
|
|
newChildren.splice(currentIndex - 1, 0, component)
|
|
|
|
parent._children = newChildren
|
|
|
|
}
|
|
|
|
s.currentComponentInfo = component
|
|
|
|
saveCurrentPreviewItem(s)
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
return s
|
|
|
|
})
|
|
|
|
}
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
const moveDownComponent = () => {
|
|
|
|
store.update(s => {
|
|
|
|
const parent = getParent(s.currentPreviewItem.props, component)
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
if (parent) {
|
|
|
|
const currentIndex = parent._children.indexOf(component)
|
|
|
|
if (currentIndex === parent._children.length - 1) return s
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
const newChildren = parent._children.filter(c => c !== component)
|
|
|
|
newChildren.splice(currentIndex + 1, 0, component)
|
|
|
|
parent._children = newChildren
|
|
|
|
}
|
|
|
|
s.currentComponentInfo = component
|
|
|
|
saveCurrentPreviewItem(s)
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
return s
|
2020-06-01 13:12:25 +02:00
|
|
|
})
|
2020-06-01 13:15:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const copyComponent = () => {
|
2020-10-07 23:30:00 +02:00
|
|
|
storeComponentForCopy(false)
|
|
|
|
pasteComponent("below")
|
2020-06-01 13:15:44 +02:00
|
|
|
}
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
const deleteComponent = () => {
|
|
|
|
store.update(state => {
|
|
|
|
const parent = getParent(state.currentPreviewItem.props, component)
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
if (parent) {
|
|
|
|
parent._children = parent._children.filter(c => c !== component)
|
2020-10-13 10:06:56 +02:00
|
|
|
selectComponent(parent)
|
2020-06-01 13:15:44 +02:00
|
|
|
}
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
saveCurrentPreviewItem(state)
|
|
|
|
return state
|
|
|
|
})
|
|
|
|
}
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
const storeComponentForCopy = (cut = false) => {
|
2020-08-12 17:28:19 +02:00
|
|
|
// lives in store - also used by drag drop
|
|
|
|
store.storeComponentForCopy(component, cut)
|
2020-06-01 13:15:44 +02:00
|
|
|
}
|
2020-06-01 13:12:25 +02:00
|
|
|
|
2020-06-01 13:15:44 +02:00
|
|
|
const pasteComponent = mode => {
|
2020-08-12 17:28:19 +02:00
|
|
|
// lives in store - also used by drag drop
|
|
|
|
store.pasteComponent(component, mode)
|
2020-06-01 13:15:44 +02:00
|
|
|
}
|
2020-06-01 11:18:45 +02:00
|
|
|
</script>
|
|
|
|
|
2020-09-07 00:50:11 +02:00
|
|
|
<div bind:this={anchor} on:click|stopPropagation={() => {}}>
|
2020-10-14 14:21:43 +02:00
|
|
|
<div class="icon" on:click={dropdown.show}><i class="ri-more-line" /></div>
|
2020-09-07 00:50:11 +02:00
|
|
|
</div>
|
|
|
|
<DropdownMenu
|
|
|
|
bind:this={dropdown}
|
|
|
|
on:click={hideDropdown}
|
|
|
|
width="170px"
|
|
|
|
{anchor}
|
|
|
|
align="left">
|
|
|
|
<ul>
|
2020-06-01 23:16:55 +02:00
|
|
|
<li class="item" on:click={() => confirmDeleteDialog.show()}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-delete-bin-2-line" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Delete
|
|
|
|
</li>
|
|
|
|
<li class="item" on:click={moveUpComponent}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-arrow-up-line" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Move up
|
|
|
|
</li>
|
|
|
|
<li class="item" on:click={moveDownComponent}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-arrow-down-line" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Move down
|
|
|
|
</li>
|
|
|
|
<li class="item" on:click={copyComponent}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-repeat-one-line" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Duplicate
|
|
|
|
</li>
|
|
|
|
<li class="item" on:click={() => storeComponentForCopy(true)}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-scissors-cut-line" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Cut
|
|
|
|
</li>
|
|
|
|
<li class="item" on:click={() => storeComponentForCopy(false)}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-file-copy-line" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Copy
|
|
|
|
</li>
|
|
|
|
<hr class="hr-style" />
|
|
|
|
<li
|
|
|
|
class="item"
|
|
|
|
class:disabled={noPaste}
|
|
|
|
on:click={() => pasteComponent('above')}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-insert-row-top" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Paste above
|
|
|
|
</li>
|
|
|
|
<li
|
|
|
|
class="item"
|
|
|
|
class:disabled={noPaste}
|
|
|
|
on:click={() => pasteComponent('below')}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-insert-row-bottom" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Paste below
|
|
|
|
</li>
|
|
|
|
<li
|
|
|
|
class="item"
|
|
|
|
class:disabled={noPaste || noChildrenAllowed}
|
|
|
|
on:click={() => pasteComponent('inside')}>
|
2020-10-04 18:10:32 +02:00
|
|
|
<i class="ri-insert-column-right" />
|
2020-06-01 23:16:55 +02:00
|
|
|
Paste inside
|
|
|
|
</li>
|
2020-09-07 00:50:11 +02:00
|
|
|
</ul>
|
|
|
|
</DropdownMenu>
|
2020-06-01 11:18:45 +02:00
|
|
|
|
|
|
|
<ConfirmDialog
|
|
|
|
bind:this={confirmDeleteDialog}
|
|
|
|
title="Confirm Delete"
|
|
|
|
body={`Are you sure you wish to delete this '${lastPartOfName(component)}' component?`}
|
|
|
|
okText="Delete Component"
|
2020-06-01 13:12:25 +02:00
|
|
|
onOk={deleteComponent} />
|
2020-06-01 11:18:45 +02:00
|
|
|
|
|
|
|
<style>
|
2020-09-07 00:50:11 +02:00
|
|
|
ul {
|
|
|
|
list-style: none;
|
|
|
|
padding: 0;
|
2020-10-04 18:10:32 +02:00
|
|
|
margin: var(--spacing-s) 0;
|
2020-09-07 00:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
li {
|
|
|
|
display: flex;
|
|
|
|
font-family: var(--font-sans);
|
|
|
|
font-size: var(--font-size-xs);
|
|
|
|
color: var(--ink);
|
|
|
|
padding: var(--spacing-s) var(--spacing-m);
|
2020-10-04 18:10:32 +02:00
|
|
|
margin: auto 0;
|
2020-09-07 00:50:11 +02:00
|
|
|
align-items: center;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
2020-10-04 18:10:32 +02:00
|
|
|
li:not(.disabled):hover {
|
2020-09-07 00:50:11 +02:00
|
|
|
background-color: var(--grey-2);
|
|
|
|
}
|
|
|
|
li:active {
|
|
|
|
color: var(--blue);
|
2020-06-01 13:15:44 +02:00
|
|
|
}
|
2020-10-04 18:10:32 +02:00
|
|
|
li i {
|
2020-06-01 16:31:55 +02:00
|
|
|
margin-right: 8px;
|
2020-10-04 18:10:32 +02:00
|
|
|
font-size: var(--font-size-s);
|
2020-06-01 16:31:55 +02:00
|
|
|
}
|
2020-10-04 18:10:32 +02:00
|
|
|
li.disabled {
|
2020-06-23 09:19:16 +02:00
|
|
|
color: var(--grey-4);
|
2020-06-01 13:15:44 +02:00
|
|
|
cursor: default;
|
|
|
|
}
|
2020-06-01 16:31:55 +02:00
|
|
|
|
2020-10-04 18:10:32 +02:00
|
|
|
.icon i {
|
|
|
|
font-size: 16px;
|
|
|
|
}
|
|
|
|
|
2020-06-01 16:31:55 +02:00
|
|
|
.hr-style {
|
|
|
|
margin: 8px 0;
|
2020-06-23 09:19:16 +02:00
|
|
|
color: var(--grey-4);
|
2020-06-01 16:31:55 +02:00
|
|
|
}
|
2020-06-01 13:15:44 +02:00
|
|
|
</style>
|