Merge pull request #108 from mjashanks/master
#94 Remove components from hierarchy
This commit is contained in:
commit
09cfb169d6
File diff suppressed because one or more lines are too long
|
@ -115,6 +115,7 @@ export const getStore = () => {
|
||||||
store.setComponentStyle = setComponentStyle(store)
|
store.setComponentStyle = setComponentStyle(store)
|
||||||
store.setComponentCode = setComponentCode(store)
|
store.setComponentCode = setComponentCode(store)
|
||||||
store.setScreenType = setScreenType(store)
|
store.setScreenType = setScreenType(store)
|
||||||
|
store.deleteComponent = deleteComponent(store)
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -837,3 +838,39 @@ const setScreenType = store => type => {
|
||||||
return s
|
return s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteComponent = store => component => {
|
||||||
|
store.update(s => {
|
||||||
|
let parent
|
||||||
|
walkProps(s.currentPreviewItem.props, (p, breakWalk) => {
|
||||||
|
if (p._children.includes(component)) {
|
||||||
|
parent = p
|
||||||
|
breakWalk()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
parent._children = parent._children.filter(c => c !== component)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.currentFrontEndType === "page"
|
||||||
|
? _savePage(s)
|
||||||
|
: _saveScreenApi(s.currentPreviewItem, s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const walkProps = (props, action, cancelToken = null) => {
|
||||||
|
cancelToken = cancelToken || { cancelled: false }
|
||||||
|
action(props, () => {
|
||||||
|
cancelToken.cancelled = true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (props._children) {
|
||||||
|
for (let child of props._children) {
|
||||||
|
if (cancelToken.cancelled) return
|
||||||
|
walkProps(child, action, cancelToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import Button from "./Button.svelte"
|
||||||
|
import ButtonGroup from "./ButtonGroup.svelte"
|
||||||
|
import UIkit from "uikit"
|
||||||
|
|
||||||
|
export let title=""
|
||||||
|
export let body=""
|
||||||
|
export let okText = "OK"
|
||||||
|
export let cancelText = "Cancel"
|
||||||
|
export let onOk = ()=> {}
|
||||||
|
export let onCancel = ()=> {}
|
||||||
|
|
||||||
|
export const show = () => {
|
||||||
|
UIkit.modal(theModal).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hide = () => {
|
||||||
|
UIkit.modal(theModal).hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
let theModal;
|
||||||
|
|
||||||
|
const cancel = () => {
|
||||||
|
hide()
|
||||||
|
onCancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
const ok = () => {
|
||||||
|
hide()
|
||||||
|
onOk()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="my-id" uk-modal bind:this={theModal}>
|
||||||
|
<div class="uk-modal-dialog">
|
||||||
|
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||||
|
<div class="uk-modal-header">
|
||||||
|
<h2 class="uk-modal-title">{title}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="uk-modal-body">{body}</div>
|
||||||
|
<div class="uk-modal-footer">
|
||||||
|
<ButtonGroup>
|
||||||
|
<Button grouped color="primary" on:click={ok}>
|
||||||
|
{okText}
|
||||||
|
</Button>
|
||||||
|
<Button grouped color="secondary" on:click={cancel}>
|
||||||
|
{cancelText}
|
||||||
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="feather feather-x-circle">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<line x1="15" y1="9" x2="9" y2="15"/>
|
||||||
|
<line x1="9" y1="9" x2="15" y2="15"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
svg {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
After Width: | Height: | Size: 454 B |
|
@ -7,3 +7,4 @@ export { default as ArrowDownIcon } from "./ArrowDown.svelte"
|
||||||
export { default as CircleIndicator } from "./CircleIndicator.svelte"
|
export { default as CircleIndicator } from "./CircleIndicator.svelte"
|
||||||
export { default as PencilIcon } from "./Pencil.svelte"
|
export { default as PencilIcon } from "./Pencil.svelte"
|
||||||
export { default as EventsIcon } from "./Events.svelte"
|
export { default as EventsIcon } from "./Events.svelte"
|
||||||
|
export { default as XCircleIcon } from "./XCircle.svelte"
|
||||||
|
|
|
@ -2,13 +2,16 @@
|
||||||
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
||||||
|
|
||||||
import { last, sortBy, map, trimCharsStart, trimChars, join } from "lodash/fp"
|
import { last, sortBy, map, trimCharsStart, trimChars, join } from "lodash/fp"
|
||||||
|
import ConfirmDialog from "../common/ConfirmDialog.svelte"
|
||||||
import { pipe } from "../common/core"
|
import { pipe } from "../common/core"
|
||||||
import { store } from "../builderStore"
|
import { store } from "../builderStore"
|
||||||
import { ArrowDownIcon } from "../common/Icons/"
|
import { ArrowDownIcon } from "../common/Icons/"
|
||||||
|
|
||||||
export let screens = []
|
export let screens = []
|
||||||
|
|
||||||
|
let confirmDeleteDialog
|
||||||
|
let componentToDelete = ""
|
||||||
|
|
||||||
const joinPath = join("/")
|
const joinPath = join("/")
|
||||||
|
|
||||||
const normalizedName = name =>
|
const normalizedName = name =>
|
||||||
|
@ -23,6 +26,7 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
const lastPartOfName = c =>
|
const lastPartOfName = c =>
|
||||||
|
c &&
|
||||||
last(c.name ? c.name.split("/") : c._component.split("/"))
|
last(c.name ? c.name.split("/") : c._component.split("/"))
|
||||||
|
|
||||||
const isComponentSelected = (current, comp) => current === comp
|
const isComponentSelected = (current, comp) => current === comp
|
||||||
|
@ -38,6 +42,12 @@
|
||||||
component.component &&
|
component.component &&
|
||||||
$store.currentPreviewItem &&
|
$store.currentPreviewItem &&
|
||||||
component.component.name === $store.currentPreviewItem.name
|
component.component.name === $store.currentPreviewItem.name
|
||||||
|
|
||||||
|
const confirmDeleteComponent = component => {
|
||||||
|
componentToDelete = component
|
||||||
|
confirmDeleteDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
@ -63,12 +73,20 @@
|
||||||
<ComponentsHierarchyChildren
|
<ComponentsHierarchyChildren
|
||||||
components={screen.component.props._children}
|
components={screen.component.props._children}
|
||||||
currentComponent={$store.currentComponentInfo}
|
currentComponent={$store.currentComponentInfo}
|
||||||
onSelect={store.selectComponent} />
|
onSelect={store.selectComponent}
|
||||||
|
onDeleteComponent={confirmDeleteComponent}/>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:this={confirmDeleteDialog}
|
||||||
|
title="Confirm Delete"
|
||||||
|
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete._component)}' component`}
|
||||||
|
okText="Delete Component"
|
||||||
|
onOk={() => store.deleteComponent(componentToDelete)}/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.root {
|
.root {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
<script>
|
<script>
|
||||||
import { last } from "lodash/fp"
|
import { last } from "lodash/fp"
|
||||||
import { pipe } from "../common/core"
|
import { pipe } from "../common/core"
|
||||||
|
import { XCircleIcon } from "../common/Icons"
|
||||||
|
|
||||||
export let components = []
|
export let components = []
|
||||||
export let currentComponent
|
export let currentComponent
|
||||||
export let onSelect = () => {}
|
export let onSelect = () => {}
|
||||||
export let level = 0
|
export let level = 0
|
||||||
|
export let onDeleteComponent
|
||||||
|
|
||||||
|
|
||||||
const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1)
|
const capitalise = s => s.substring(0, 1).toUpperCase() + s.substring(1)
|
||||||
const get_name = s => last(s.split("/"))
|
const get_name = s => !s ? "" : last(s.split("/"))
|
||||||
|
|
||||||
const get_capitalised_name = name =>
|
const get_capitalised_name = name =>
|
||||||
pipe(
|
pipe(
|
||||||
name,
|
name,
|
||||||
[get_name, capitalise]
|
[get_name, capitalise]
|
||||||
)
|
)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -24,7 +28,12 @@
|
||||||
class="item"
|
class="item"
|
||||||
class:selected={currentComponent === component}
|
class:selected={currentComponent === component}
|
||||||
style="padding-left: {level * 20 + 67}px">
|
style="padding-left: {level * 20 + 67}px">
|
||||||
{get_capitalised_name(component._component)}
|
<span class="item-name">{get_capitalised_name(component._component)}</span>
|
||||||
|
<button
|
||||||
|
class="delete-component"
|
||||||
|
on:click={() => onDeleteComponent(component)}>
|
||||||
|
<XCircleIcon />
|
||||||
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{#if component._children}
|
{#if component._children}
|
||||||
|
@ -32,7 +41,8 @@
|
||||||
components={component._children}
|
components={component._children}
|
||||||
{currentComponent}
|
{currentComponent}
|
||||||
{onSelect}
|
{onSelect}
|
||||||
level={level + 1} />
|
level={level + 1}
|
||||||
|
{onDeleteComponent} />
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -45,14 +55,39 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.item {
|
.item {
|
||||||
display: block;
|
display: flex;
|
||||||
padding: 11px 67px;
|
flex-direction: row;
|
||||||
|
padding: 11px 5px 11px 67px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item > span {
|
||||||
|
width: 1px;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item > button {
|
||||||
|
display: none;
|
||||||
|
height: 20px;
|
||||||
|
color: var(--slate)
|
||||||
|
}
|
||||||
|
|
||||||
.item:hover {
|
.item:hover {
|
||||||
|
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.item:hover > button {
|
||||||
|
border-style: none;
|
||||||
|
background: rgba(0,0,0,0);
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item:hover > button:hover {
|
||||||
|
color: var(--button-text);
|
||||||
|
}
|
||||||
|
|
||||||
.selected {
|
.selected {
|
||||||
color: var(--button-text);
|
color: var(--button-text);
|
||||||
background: var(--background-button) !important;
|
background: var(--background-button) !important;
|
||||||
|
|
|
@ -10,8 +10,12 @@
|
||||||
import SettingsView from "./SettingsView.svelte"
|
import SettingsView from "./SettingsView.svelte"
|
||||||
import PageView from "./PageView.svelte"
|
import PageView from "./PageView.svelte"
|
||||||
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte"
|
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte"
|
||||||
|
import ConfirmDialog from "../common/ConfirmDialog.svelte"
|
||||||
|
import { last } from "lodash/fp"
|
||||||
|
|
||||||
let newComponentPicker
|
let newComponentPicker
|
||||||
|
let confirmDeleteDialog
|
||||||
|
let componentToDelete = ""
|
||||||
|
|
||||||
const newComponent = () => {
|
const newComponent = () => {
|
||||||
newComponentPicker.show()
|
newComponentPicker.show()
|
||||||
|
@ -21,6 +25,14 @@
|
||||||
const settings = () => {
|
const settings = () => {
|
||||||
settingsView.show()
|
settingsView.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const confirmDeleteComponent = component => {
|
||||||
|
componentToDelete = component
|
||||||
|
confirmDeleteDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastPartOfName = c => c ? c.split("/") : ""
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
|
@ -53,6 +65,7 @@
|
||||||
<ComponentsHierarchyChildren
|
<ComponentsHierarchyChildren
|
||||||
components={$store.currentPreviewItem.props._children}
|
components={$store.currentPreviewItem.props._children}
|
||||||
currentComponent={$store.currentComponentInfo}
|
currentComponent={$store.currentComponentInfo}
|
||||||
|
onDeleteComponent={confirmDeleteComponent}
|
||||||
onSelect={store.selectComponent}
|
onSelect={store.selectComponent}
|
||||||
level={-2} />
|
level={-2} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -101,6 +114,13 @@
|
||||||
<NewComponent bind:this={newComponentPicker} />
|
<NewComponent bind:this={newComponentPicker} />
|
||||||
<SettingsView bind:this={settingsView} />
|
<SettingsView bind:this={settingsView} />
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:this={confirmDeleteDialog}
|
||||||
|
title="Confirm Delete"
|
||||||
|
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete._component)}' component`}
|
||||||
|
okText="Delete Component"
|
||||||
|
onOk={() => store.deleteComponent(componentToDelete)}/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
button {
|
button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -42,7 +42,11 @@ export const screenRouter = (screens, onScreenSelected) => {
|
||||||
onScreenSelected(screens[fallback], store, _url)
|
onScreenSelected(screens[fallback], store, _url)
|
||||||
}
|
}
|
||||||
|
|
||||||
!url.state && history.pushState(_url, null, _url)
|
try {
|
||||||
|
!url.state && history.pushState(_url, null, _url)
|
||||||
|
} catch (_) {
|
||||||
|
// ignoring an exception here as the builder runs an iframe, which does not like this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function click(e) {
|
function click(e) {
|
||||||
|
|
Loading…
Reference in New Issue