Update screen components hierarchy to use new common component styles
This commit is contained in:
parent
350083025d
commit
8e6b4f1aeb
|
@ -0,0 +1,108 @@
|
||||||
|
<script>
|
||||||
|
export let icon
|
||||||
|
export let withArrow = false
|
||||||
|
export let withActions = true
|
||||||
|
export let indentLevel = 0
|
||||||
|
export let text
|
||||||
|
export let border = true
|
||||||
|
export let selected = false
|
||||||
|
export let opened = false
|
||||||
|
export let draggable = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="container"
|
||||||
|
class:border
|
||||||
|
class:selected
|
||||||
|
style={`padding-left: ${indentLevel * 18}px`}
|
||||||
|
{draggable}
|
||||||
|
on:dragend
|
||||||
|
on:dragstart
|
||||||
|
on:dragover
|
||||||
|
on:drop
|
||||||
|
on:click
|
||||||
|
ondragover="return false"
|
||||||
|
ondragenter="return false">
|
||||||
|
<div class="content">
|
||||||
|
{#if withArrow}
|
||||||
|
<div class:opened class="icon arrow">
|
||||||
|
<i class="ri-arrow-right-s-fill" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if icon}
|
||||||
|
<div class="icon"><i class={icon} /></div>
|
||||||
|
{/if}
|
||||||
|
<div class="text">{text}</div>
|
||||||
|
{#if withActions}
|
||||||
|
<div class="actions">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
border-radius: var(--border-radius-m);
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--grey-7);
|
||||||
|
}
|
||||||
|
.container.border {
|
||||||
|
border-top: 1px solid var(--grey-1);
|
||||||
|
}
|
||||||
|
.container.selected {
|
||||||
|
background-color: var(--grey-2);
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
.container:hover {
|
||||||
|
background-color: var(--grey-1);
|
||||||
|
}
|
||||||
|
.container:hover .actions {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 var(--spacing-m);
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 16px;
|
||||||
|
flex: 0 0 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.icon.arrow {
|
||||||
|
margin: 0 -2px 0 -6px;
|
||||||
|
}
|
||||||
|
.icon.arrow.opened {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
.icon + .icon {
|
||||||
|
margin-left: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,13 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { params, goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
||||||
import { last, sortBy, map, trimCharsStart, trimChars, join } from "lodash/fp"
|
import { trimCharsStart, trimChars } from "lodash/fp"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
|
||||||
import { pipe } from "components/common/core"
|
import { pipe } from "components/common/core"
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { ArrowDownIcon, ShapeIcon } from "components/common/Icons/"
|
|
||||||
import ScreenDropdownMenu from "./ScreenDropdownMenu.svelte"
|
import ScreenDropdownMenu from "./ScreenDropdownMenu.svelte"
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
|
|
||||||
export let screens = []
|
export let screens = []
|
||||||
|
|
||||||
|
@ -24,9 +23,7 @@
|
||||||
let confirmDeleteDialog
|
let confirmDeleteDialog
|
||||||
let componentToDelete = ""
|
let componentToDelete = ""
|
||||||
|
|
||||||
const joinPath = join("/")
|
const normalizedName = (name) =>
|
||||||
|
|
||||||
const normalizedName = name =>
|
|
||||||
pipe(name, [
|
pipe(name, [
|
||||||
trimCharsStart("./"),
|
trimCharsStart("./"),
|
||||||
trimCharsStart("~/"),
|
trimCharsStart("~/"),
|
||||||
|
@ -34,7 +31,7 @@
|
||||||
trimChars(" "),
|
trimChars(" "),
|
||||||
])
|
])
|
||||||
|
|
||||||
const changeScreen = screen => {
|
const changeScreen = (screen) => {
|
||||||
store.setCurrentScreen(screen.props._instanceName)
|
store.setCurrentScreen(screen.props._instanceName)
|
||||||
$goto(`./:page/${screen.props._instanceName}`)
|
$goto(`./:page/${screen.props._instanceName}`)
|
||||||
}
|
}
|
||||||
|
@ -42,26 +39,15 @@
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
{#each sortedScreens as screen}
|
{#each sortedScreens as screen}
|
||||||
<div
|
<NavItem
|
||||||
class="budibase__nav-item screen-header-row"
|
icon="ri-artboard-2-line"
|
||||||
class:selected={$store.currentComponentInfo._id === screen.props._id}
|
text={screen.props._instanceName}
|
||||||
on:click|stopPropagation={() => changeScreen(screen)}>
|
withArrow={screen.props._children.length}
|
||||||
<span
|
selected={$store.currentComponentInfo._id === screen.props._id}
|
||||||
class="icon"
|
opened={$store.currentPreviewItem.name !== screen.props._id}
|
||||||
class:rotate={$store.currentPreviewItem.name !== screen.props._instanceName}>
|
on:click={() => changeScreen(screen)}>
|
||||||
{#if screen.props._children.length}
|
<ScreenDropdownMenu {screen} />
|
||||||
<ArrowDownIcon />
|
</NavItem>
|
||||||
{/if}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<i class="ri-artboard-2-fill icon" />
|
|
||||||
|
|
||||||
<span class="title">{screen.props._instanceName}</span>
|
|
||||||
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<ScreenDropdownMenu {screen} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if $store.currentPreviewItem.props._instanceName && $store.currentPreviewItem.props._instanceName === screen.props._instanceName && screen.props._children}
|
{#if $store.currentPreviewItem.props._instanceName && $store.currentPreviewItem.props._instanceName === screen.props._instanceName && screen.props._children}
|
||||||
<ComponentsHierarchyChildren
|
<ComponentsHierarchyChildren
|
||||||
|
@ -71,55 +57,3 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
font-weight: 400;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.screen-header-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin-left: 14px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
display: inline-block;
|
|
||||||
transition: 0.2s;
|
|
||||||
font-size: 24px;
|
|
||||||
width: 18px;
|
|
||||||
color: var(--grey-7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon:nth-of-type(2) {
|
|
||||||
width: 14px;
|
|
||||||
margin: 0 0 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rotate :global(svg) {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
display: none;
|
|
||||||
color: var(--ink);
|
|
||||||
padding: 0 5px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-style: none;
|
|
||||||
background: rgba(0, 0, 0, 0);
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budibase__nav-item:hover .dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -4,12 +4,7 @@
|
||||||
import { last } from "lodash/fp"
|
import { last } from "lodash/fp"
|
||||||
import { pipe } from "components/common/core"
|
import { pipe } from "components/common/core"
|
||||||
import ComponentDropdownMenu from "./ComponentDropdownMenu.svelte"
|
import ComponentDropdownMenu from "./ComponentDropdownMenu.svelte"
|
||||||
import {
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
XCircleIcon,
|
|
||||||
ChevronUpIcon,
|
|
||||||
ChevronDownIcon,
|
|
||||||
CopyIcon,
|
|
||||||
} from "../common/Icons"
|
|
||||||
import { getComponentDefinition } from "builderStore/storeUtils"
|
import { getComponentDefinition } from "builderStore/storeUtils"
|
||||||
|
|
||||||
export let components = []
|
export let components = []
|
||||||
|
@ -38,13 +33,12 @@
|
||||||
let dropUnderComponent
|
let dropUnderComponent
|
||||||
let componentToDrop
|
let componentToDrop
|
||||||
|
|
||||||
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 => (!s ? "" : last(s.split("/")))
|
const get_name = (s) => (!s ? "" : last(s.split("/")))
|
||||||
|
const get_capitalised_name = (name) => pipe(name, [get_name, capitalise])
|
||||||
|
const isScreenslot = (name) => name === "##builtin/screenslot"
|
||||||
|
|
||||||
const get_capitalised_name = name => pipe(name, [get_name, capitalise])
|
const selectComponent = (component) => {
|
||||||
const isScreenslot = name => name === "##builtin/screenslot"
|
|
||||||
|
|
||||||
const selectComponent = component => {
|
|
||||||
// Set current component
|
// Set current component
|
||||||
store.selectComponent(component)
|
store.selectComponent(component)
|
||||||
|
|
||||||
|
@ -55,21 +49,21 @@
|
||||||
$goto(`./:page/:screen/${path}`)
|
$goto(`./:page/:screen/${path}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragstart = component => e => {
|
const dragstart = (component) => (e) => {
|
||||||
e.dataTransfer.dropEffect = "move"
|
e.dataTransfer.dropEffect = "move"
|
||||||
dragDropStore.update(s => {
|
dragDropStore.update((s) => {
|
||||||
s.componentToDrop = component
|
s.componentToDrop = component
|
||||||
return s
|
return s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragover = (component, index) => e => {
|
const dragover = (component, index) => (e) => {
|
||||||
const canHaveChildrenButIsEmpty =
|
const canHaveChildrenButIsEmpty =
|
||||||
getComponentDefinition($store, component._component).children &&
|
getComponentDefinition($store, component._component).children &&
|
||||||
component._children.length === 0
|
component._children.length === 0
|
||||||
|
|
||||||
e.dataTransfer.dropEffect = "copy"
|
e.dataTransfer.dropEffect = "copy"
|
||||||
dragDropStore.update(s => {
|
dragDropStore.update((s) => {
|
||||||
const isBottomHalf = e.offsetY > e.currentTarget.offsetHeight / 2
|
const isBottomHalf = e.offsetY > e.currentTarget.offsetHeight / 2
|
||||||
s.targetComponent = component
|
s.targetComponent = component
|
||||||
// only allow dropping inside when container type
|
// only allow dropping inside when container type
|
||||||
|
@ -108,7 +102,7 @@
|
||||||
$dragDropStore.dropPosition
|
$dragDropStore.dropPosition
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
dragDropStore.update(s => {
|
dragDropStore.update((s) => {
|
||||||
s.dropPosition = ""
|
s.dropPosition = ""
|
||||||
s.targetComponent = null
|
s.targetComponent = null
|
||||||
s.componentToDrop = null
|
s.componentToDrop = null
|
||||||
|
@ -117,7 +111,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragend = () => {
|
const dragend = () => {
|
||||||
dragDropStore.update(s => {
|
dragDropStore.update((s) => {
|
||||||
s.dropPosition = ""
|
s.dropPosition = ""
|
||||||
s.targetComponent = null
|
s.targetComponent = null
|
||||||
s.componentToDrop = null
|
s.componentToDrop = null
|
||||||
|
@ -134,29 +128,22 @@
|
||||||
on:drop={drop}
|
on:drop={drop}
|
||||||
ondragover="return false"
|
ondragover="return false"
|
||||||
ondragenter="return false"
|
ondragenter="return false"
|
||||||
class="budibase__nav-item item drop-item"
|
class="drop-item"
|
||||||
style="margin-left: {level * 20 + 40}px" />
|
style="margin-left: {(level + 1) * 18}px" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<NavItem
|
||||||
class="budibase__nav-item item"
|
draggable
|
||||||
class:selected={currentComponent === component}
|
|
||||||
style="padding-left: {level * 20 + 40}px"
|
|
||||||
draggable={true}
|
|
||||||
on:dragend={dragend}
|
on:dragend={dragend}
|
||||||
on:dragstart={dragstart(component)}
|
on:dragstart={dragstart(component)}
|
||||||
on:dragover={dragover(component, index)}
|
on:dragover={dragover(component, index)}
|
||||||
on:drop={drop}
|
on:drop={drop}
|
||||||
ondragover="return false"
|
text={isScreenslot(component._component) ? 'Screenslot' : component._instanceName}
|
||||||
ondragenter="return false">
|
withArrow
|
||||||
<div class="nav-item">
|
indentLevel={level + 1}
|
||||||
<i class="icon ri-arrow-right-circle-line" />
|
selected={currentComponent === component}>
|
||||||
{isScreenslot(component._component) ? 'Screenslot' : component._instanceName}
|
<ComponentDropdownMenu {component} />
|
||||||
</div>
|
</NavItem>
|
||||||
<div class="actions">
|
|
||||||
<ComponentDropdownMenu {component} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if component._children}
|
{#if component._children}
|
||||||
<svelte:self
|
<svelte:self
|
||||||
|
@ -172,8 +159,8 @@
|
||||||
on:drop={drop}
|
on:drop={drop}
|
||||||
ondragover="return false"
|
ondragover="return false"
|
||||||
ondragenter="return false"
|
ondragenter="return false"
|
||||||
class="budibase__nav-item item drop-item"
|
class="drop-item"
|
||||||
style="margin-left: {(level + ($dragDropStore.dropPosition === 'inside' ? 2 : 0)) * 20 + 40}px" />
|
style="margin-left: {(level + ($dragDropStore.dropPosition === 'inside' ? 3 : 1)) * 18}px" />
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -186,47 +173,9 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr auto auto auto;
|
|
||||||
padding: 0 var(--spacing-m);
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
height: 36px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drop-item {
|
.drop-item {
|
||||||
|
border-radius: var(--border-radius-m);
|
||||||
|
height: 32px;
|
||||||
background: var(--blue-light);
|
background: var(--blue-light);
|
||||||
height: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: none;
|
|
||||||
color: var(--ink);
|
|
||||||
border-style: none;
|
|
||||||
background: rgba(0, 0, 0, 0);
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item:hover {
|
|
||||||
background: var(--grey-1);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.item:hover .actions {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
color: var(--grey-7);
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,21 +1,9 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
import { goto } from "@sveltech/routify"
|
||||||
// import { tick } from "svelte"
|
|
||||||
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
||||||
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
import {
|
import { last } from "lodash/fp"
|
||||||
last,
|
|
||||||
sortBy,
|
|
||||||
map,
|
|
||||||
trimCharsStart,
|
|
||||||
trimChars,
|
|
||||||
join,
|
|
||||||
compose,
|
|
||||||
} from "lodash/fp"
|
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
|
||||||
import { pipe } from "components/common/core"
|
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { ArrowDownIcon, GridIcon } from "components/common/Icons/"
|
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
|
|
||||||
export let layout
|
export let layout
|
||||||
|
@ -24,13 +12,10 @@
|
||||||
let componentToDelete = ""
|
let componentToDelete = ""
|
||||||
|
|
||||||
const dragDropStore = writable({})
|
const dragDropStore = writable({})
|
||||||
const joinPath = join("/")
|
|
||||||
|
|
||||||
const lastPartOfName = c =>
|
const lastPartOfName = (c) =>
|
||||||
c && last(c.name ? c.name.split("/") : c._component.split("/"))
|
c && last(c.name ? c.name.split("/") : c._component.split("/"))
|
||||||
|
|
||||||
const isComponentSelected = (current, comp) => current === comp
|
|
||||||
|
|
||||||
$: _layout = {
|
$: _layout = {
|
||||||
component: layout,
|
component: layout,
|
||||||
title: lastPartOfName(layout),
|
title: lastPartOfName(layout),
|
||||||
|
@ -42,18 +27,14 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<NavItem
|
||||||
class="budibase__nav-item root"
|
border={false}
|
||||||
class:selected={$store.currentComponentInfo._id === _layout.component.props._id}
|
icon="ri-layout-3-line"
|
||||||
on:click|stopPropagation={setCurrentScreenToLayout}>
|
text="Master Screen"
|
||||||
<span
|
withArrow
|
||||||
class="icon"
|
selected={$store.currentComponentInfo._id === _layout.component.props._id}
|
||||||
class:rotate={$store.currentPreviewItem.name !== _layout.title}>
|
opened={$store.currentPreviewItem.name === _layout.title}
|
||||||
<ArrowDownIcon />
|
on:click={setCurrentScreenToLayout} />
|
||||||
</span>
|
|
||||||
<i class="ri-layout-3-fill icon-big" />
|
|
||||||
<span class="title">Master Screen</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if $store.currentPreviewItem.name === _layout.title && _layout.component.props._children}
|
{#if $store.currentPreviewItem.name === _layout.title && _layout.component.props._children}
|
||||||
<ComponentsHierarchyChildren
|
<ComponentsHierarchyChildren
|
||||||
|
@ -62,29 +43,3 @@
|
||||||
currentComponent={$store.currentComponentInfo}
|
currentComponent={$store.currentComponentInfo}
|
||||||
{dragDropStore} />
|
{dragDropStore} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
|
||||||
.title {
|
|
||||||
margin-left: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 24px;
|
|
||||||
display: inline-block;
|
|
||||||
transition: 0.2s;
|
|
||||||
width: 20px;
|
|
||||||
color: var(--grey-7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-big {
|
|
||||||
font-size: 20px;
|
|
||||||
color: var(--grey-7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rotate :global(svg) {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
Loading…
Reference in New Issue