Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#94 Remove components from hierarchy #108

Merged
merged 2 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions packages/bootstrap-components/dist/generators.js

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions packages/builder/src/builderStore/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export const getStore = () => {
store.setComponentStyle = setComponentStyle(store)
store.setComponentCode = setComponentCode(store)
store.setScreenType = setScreenType(store)
store.deleteComponent = deleteComponent(store)
return store
}

Expand Down Expand Up @@ -837,3 +838,39 @@ const setScreenType = store => type => {
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)
}
}
}
55 changes: 55 additions & 0 deletions packages/builder/src/common/ConfirmDialog.svelte
Original file line number Diff line number Diff line change
@@ -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>

23 changes: 23 additions & 0 deletions packages/builder/src/common/Icons/XCircle.svelte
Original file line number Diff line number Diff line change
@@ -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>
1 change: 1 addition & 0 deletions packages/builder/src/common/Icons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { default as ArrowDownIcon } from "./ArrowDown.svelte"
export { default as CircleIndicator } from "./CircleIndicator.svelte"
export { default as PencilIcon } from "./Pencil.svelte"
export { default as EventsIcon } from "./Events.svelte"
export { default as XCircleIcon } from "./XCircle.svelte"
22 changes: 20 additions & 2 deletions packages/builder/src/userInterface/ComponentsHierarchy.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"

import { last, sortBy, map, trimCharsStart, trimChars, join } from "lodash/fp"

import ConfirmDialog from "../common/ConfirmDialog.svelte"
import { pipe } from "../common/core"
import { store } from "../builderStore"
import { ArrowDownIcon } from "../common/Icons/"

export let screens = []

let confirmDeleteDialog
let componentToDelete = ""

const joinPath = join("/")

const normalizedName = name =>
Expand All @@ -23,6 +26,7 @@
)

const lastPartOfName = c =>
c &&
last(c.name ? c.name.split("/") : c._component.split("/"))

const isComponentSelected = (current, comp) => current === comp
Expand All @@ -38,6 +42,12 @@
component.component &&
$store.currentPreviewItem &&
component.component.name === $store.currentPreviewItem.name

const confirmDeleteComponent = component => {
componentToDelete = component
confirmDeleteDialog.show()
}

</script>

<div class="root">
Expand All @@ -63,12 +73,20 @@
<ComponentsHierarchyChildren
components={screen.component.props._children}
currentComponent={$store.currentComponentInfo}
onSelect={store.selectComponent} />
onSelect={store.selectComponent}
onDeleteComponent={confirmDeleteComponent}/>
{/if}
{/each}

</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>
.root {
font-weight: 500;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
<script>
import { last } from "lodash/fp"
import { pipe } from "../common/core"
import { XCircleIcon } from "../common/Icons"

export let components = []
export let currentComponent
export let onSelect = () => {}
export let level = 0
export let onDeleteComponent


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 =>
pipe(
name,
[get_name, capitalise]
)

</script>

<ul>
Expand All @@ -24,15 +28,21 @@
class="item"
class:selected={currentComponent === component}
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>

{#if component._children}
<svelte:self
components={component._children}
{currentComponent}
{onSelect}
level={level + 1} />
level={level + 1}
{onDeleteComponent} />
{/if}
</li>
{/each}
Expand All @@ -45,14 +55,39 @@
margin: 0;
}
.item {
display: block;
padding: 11px 67px;
display: flex;
flex-direction: row;
padding: 11px 5px 11px 67px;
border-radius: 3px;
}

.item > span {
width: 1px;
flex: 1 1 auto;
}

.item > button {
display: none;
height: 20px;
color: var(--slate)
}

.item:hover {

background: #fafafa;
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 {
color: var(--button-text);
background: var(--background-button) !important;
Expand Down
20 changes: 20 additions & 0 deletions packages/builder/src/userInterface/UserInterfaceRoot.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
import SettingsView from "./SettingsView.svelte"
import PageView from "./PageView.svelte"
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte"
import ConfirmDialog from "../common/ConfirmDialog.svelte"
import { last } from "lodash/fp"

let newComponentPicker
let confirmDeleteDialog
let componentToDelete = ""

const newComponent = () => {
newComponentPicker.show()
Expand All @@ -21,6 +25,14 @@
const settings = () => {
settingsView.show()
}

const confirmDeleteComponent = component => {
componentToDelete = component
confirmDeleteDialog.show()
}

const lastPartOfName = c => c ? c.split("/") : ""

</script>

<div class="root">
Expand Down Expand Up @@ -53,6 +65,7 @@
<ComponentsHierarchyChildren
components={$store.currentPreviewItem.props._children}
currentComponent={$store.currentComponentInfo}
onDeleteComponent={confirmDeleteComponent}
onSelect={store.selectComponent}
level={-2} />
{/if}
Expand Down Expand Up @@ -101,6 +114,13 @@
<NewComponent bind:this={newComponentPicker} />
<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>
button {
cursor: pointer;
Expand Down
6 changes: 5 additions & 1 deletion packages/client/src/render/screenRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ export const screenRouter = (screens, onScreenSelected) => {
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) {
Expand Down