Merge pull request #108 from mjashanks/master

#94 Remove components from hierarchy
This commit is contained in:
Michael Shanks 2020-02-18 16:52:55 +00:00 committed by GitHub
commit 30f05eeed6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 208 additions and 15 deletions

File diff suppressed because one or more lines are too long

View File

@ -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)
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -42,7 +42,11 @@ export const screenRouter = (screens, onScreenSelected) => {
onScreenSelected(screens[fallback], store, _url) onScreenSelected(screens[fallback], store, _url)
} }
try {
!url.state && history.pushState(_url, null, _url) !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) {