Merge branch 'property-panel/structure' into property-panel/new-backend
This commit is contained in:
commit
dc21bcd525
|
@ -2,7 +2,7 @@
|
||||||
import { onMount, beforeUpdate, afterUpdate } from "svelte"
|
import { onMount, beforeUpdate, afterUpdate } from "svelte"
|
||||||
|
|
||||||
export let value = null
|
export let value = null
|
||||||
export let onChanged = () => {}
|
export let onChange = () => {}
|
||||||
export let swatches = []
|
export let swatches = []
|
||||||
|
|
||||||
let picker
|
let picker
|
||||||
|
@ -58,13 +58,10 @@
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
getRecentColors()
|
getRecentColors()
|
||||||
createPicker()
|
createPicker()
|
||||||
|
return () => {
|
||||||
picker.on("save", (colour, instance) => {
|
picker.destroyAndRemove()
|
||||||
let color = colour.toHEXA().toString()
|
picker = null
|
||||||
onChanged(color)
|
}
|
||||||
setRecentColor(color)
|
|
||||||
picker.hide()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
export let value = ""
|
export let value = ""
|
||||||
|
export let width = ""
|
||||||
|
|
||||||
|
let style = { width }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<input type="text" on:change bind:value />
|
<input type="text" style={`width: ${width};`} on:change bind:value />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
input {
|
input {
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script>
|
||||||
|
export let categories = []
|
||||||
|
export let selectedCategory = {}
|
||||||
|
export let onClick = category => {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class="tabs">
|
||||||
|
{#each categories as category}
|
||||||
|
<li
|
||||||
|
on:click={() => onClick(category)}
|
||||||
|
class:active={selectedCategory === category}>
|
||||||
|
{category.name}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 30px;
|
||||||
|
border-bottom: 1px solid #d8d8d8;
|
||||||
|
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
color: #808192;
|
||||||
|
margin: 0 5px;
|
||||||
|
padding: 0 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
border-bottom: solid 3px #0055ff;
|
||||||
|
color: #393c44;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -13,23 +13,60 @@
|
||||||
import LayoutEditor from "./LayoutEditor.svelte"
|
import LayoutEditor from "./LayoutEditor.svelte"
|
||||||
import EventsEditor from "./EventsEditor"
|
import EventsEditor from "./EventsEditor"
|
||||||
|
|
||||||
let current_view = "props"
|
import panelStructure from "./temporaryPanelStructure.js"
|
||||||
let codeEditor
|
import CategoryTab from "./CategoryTab.svelte"
|
||||||
|
import DesignView from "./DesignView.svelte"
|
||||||
|
|
||||||
|
let current_view = "design"
|
||||||
|
let codeEditor
|
||||||
|
let flattenedPanel = flattenComponents(panelStructure.categories)
|
||||||
|
let categories = [
|
||||||
|
{ name: "Design" },
|
||||||
|
{ name: "Settings" },
|
||||||
|
{ name: "Actions" },
|
||||||
|
]
|
||||||
|
let selectedCategory = categories[0]
|
||||||
|
|
||||||
$: component = $store.currentComponentInfo
|
|
||||||
$: originalName = component.name
|
|
||||||
$: name =
|
|
||||||
$store.currentView === "detail"
|
|
||||||
? $store.currentPreviewItem.name
|
|
||||||
: component._component
|
|
||||||
$: description = component.description
|
|
||||||
$: components = $store.components
|
$: components = $store.components
|
||||||
|
$: componentInstance = $store.currentComponentInfo
|
||||||
|
$: componentDefinition = $store.components.find(
|
||||||
|
c => c.name === componentInstance._component
|
||||||
|
)
|
||||||
|
|
||||||
|
$: panelDefinition = flattenedPanel.find(
|
||||||
|
//use for getting controls for each component property
|
||||||
|
c => c._component === componentInstance._component
|
||||||
|
)
|
||||||
|
|
||||||
|
// SCREEN PROPS =============================================
|
||||||
$: screen_props =
|
$: screen_props =
|
||||||
$store.currentFrontEndType === "page"
|
$store.currentFrontEndType === "page"
|
||||||
? getProps($store.currentPreviewItem, ["name", "favicon"])
|
? getProps($store.currentPreviewItem, ["name", "favicon"])
|
||||||
: getProps($store.currentPreviewItem, ["name", "description", "route"])
|
: getProps($store.currentPreviewItem, ["name", "description", "route"])
|
||||||
|
|
||||||
const onStyleChanged = store.setComponentStyle
|
const onStyleChanged = store.setComponentStyle
|
||||||
|
const onPropChanged = store.onPropChanged
|
||||||
|
|
||||||
|
function walkProps(component, action) {
|
||||||
|
action(component)
|
||||||
|
if (component.children) {
|
||||||
|
for (let child of component.children) {
|
||||||
|
walkProps(child, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenComponents(props) {
|
||||||
|
const components = []
|
||||||
|
props.forEach(comp =>
|
||||||
|
walkProps(comp, c => {
|
||||||
|
if ("_component" in c) {
|
||||||
|
components.push(c)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return components
|
||||||
|
}
|
||||||
|
|
||||||
function getProps(obj, keys) {
|
function getProps(obj, keys) {
|
||||||
return keys.map((key, i) => [key, obj[key], obj.props._id + i])
|
return keys.map((key, i) => [key, obj[key], obj.props._id + i])
|
||||||
|
@ -37,116 +74,31 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<ul>
|
|
||||||
<li>
|
<CategoryTab
|
||||||
<button
|
onClick={category => (selectedCategory = category)}
|
||||||
class:selected={current_view === 'props'}
|
{categories}
|
||||||
on:click={() => (current_view = 'props')}>
|
{selectedCategory} />
|
||||||
<PaintIcon />
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
class:selected={current_view === 'layout'}
|
|
||||||
on:click={() => (current_view = 'layout')}>
|
|
||||||
<LayoutIcon />
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
{#if !component._component.startsWith('##')}
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
class:selected={current_view === 'code'}
|
|
||||||
on:click={() => codeEditor && codeEditor.show()}>
|
|
||||||
{#if component._code && component._code.trim().length > 0}
|
|
||||||
<div class="button-indicator">
|
|
||||||
<CircleIndicator />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<TerminalIcon />
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
class:selected={current_view === 'events'}
|
|
||||||
on:click={() => (current_view = 'events')}>
|
|
||||||
<EventsIcon />
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
||||||
</ul>
|
|
||||||
<div class="component-props-container">
|
<div class="component-props-container">
|
||||||
|
{#if current_view === 'design'}
|
||||||
{#if current_view === 'props'}
|
<DesignView
|
||||||
{#if $store.currentView === 'detail'}
|
{panelDefinition}
|
||||||
{#each screen_props as [k, v, id] (id)}
|
{componentInstance}
|
||||||
<div class="detail-prop" for={k}>
|
{componentDefinition}
|
||||||
<label>{k}:</label>
|
{onPropChanged} />
|
||||||
<input
|
|
||||||
id={k}
|
|
||||||
value={v}
|
|
||||||
on:input={({ target }) => store.setMetadataProp(k, target.value)} />
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
<PropsView {component} {components} />
|
|
||||||
{:else}
|
|
||||||
<PropsView {component} {components} />
|
|
||||||
{/if}
|
|
||||||
{:else if current_view === 'layout'}
|
|
||||||
<LayoutEditor {onStyleChanged} {component} />
|
|
||||||
{:else if current_view === 'events'}
|
|
||||||
<EventsEditor {component} {components} />
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<CodeEditor
|
|
||||||
bind:this={codeEditor}
|
|
||||||
code={component._code}
|
|
||||||
onCodeChanged={store.setComponentCode} />
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.detail-prop {
|
|
||||||
height: 40px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 1fr;
|
|
||||||
grid-template-columns: 70px 1fr;
|
|
||||||
grid-gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-prop label {
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #163057;
|
|
||||||
opacity: 0.6;
|
|
||||||
padding-top: 13px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
height: 30px;
|
|
||||||
padding-left: 8px;
|
|
||||||
padding-right: 8px;
|
|
||||||
border: 1px solid #dbdbdb;
|
|
||||||
border-radius: 2px;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus {
|
|
||||||
outline: 0;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #666;
|
|
||||||
border-color: #1e87f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title > div:nth-child(1) {
|
.title > div:nth-child(1) {
|
||||||
|
@ -162,52 +114,4 @@
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
background: none;
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li button {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 7px;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:nth-last-child(1) {
|
|
||||||
margin-right: 0px;
|
|
||||||
background: none;
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
|
||||||
color: var(--button-text);
|
|
||||||
background: #f9f9f9 !important;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-indicator {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 10px;
|
|
||||||
color: var(--button-text);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { splitName } from "./pagesParsing/splitRootComponentName.js"
|
import { splitName } from "./pagesParsing/splitRootComponentName.js"
|
||||||
import components from "./temporaryPanelStructure.js"
|
import components from "./temporaryPanelStructure.js"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
import CategoryTab from "./CategoryTab.svelte"
|
||||||
import {
|
import {
|
||||||
find,
|
find,
|
||||||
sortBy,
|
sortBy,
|
||||||
|
@ -36,15 +37,12 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<ul class="tabs">
|
|
||||||
{#each categories as category}
|
<CategoryTab
|
||||||
<li
|
onClick={category => (selectedCategory = category)}
|
||||||
on:click={() => (selectedCategory = category)}
|
{selectedCategory}
|
||||||
class:active={selectedCategory === category}>
|
{categories} />
|
||||||
{category.name}
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<Tab
|
<Tab
|
||||||
list={selectedCategory}
|
list={selectedCategory}
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
<button
|
<button
|
||||||
class:selected={selected === COMPONENT_SELECTION_TAB}
|
class:selected={selected === COMPONENT_SELECTION_TAB}
|
||||||
on:click={() => selectTab(COMPONENT_SELECTION_TAB)}>
|
on:click={() => selectTab(COMPONENT_SELECTION_TAB)}>
|
||||||
Components
|
Add
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class:selected={selected === PROPERTIES_TAB}
|
class:selected={selected === PROPERTIES_TAB}
|
||||||
on:click={() => selectTab(PROPERTIES_TAB)}>
|
on:click={() => selectTab(PROPERTIES_TAB)}>
|
||||||
Properties
|
Edit
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
|
border-left: solid 1px #e8e8ef;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switcher {
|
.switcher {
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<script>
|
||||||
|
import PropertyGroup from "./PropertyGroup.svelte"
|
||||||
|
import FlatButtonGroup from "./FlatButtonGroup.svelte"
|
||||||
|
|
||||||
|
export let panelDefinition = {}
|
||||||
|
export let componentInstance = {}
|
||||||
|
export let componentDefinition = {}
|
||||||
|
export let onPropChanged = () => {}
|
||||||
|
|
||||||
|
let selectedCategory = "desktop"
|
||||||
|
|
||||||
|
const getProperties = name => panelDefinition.properties[name]
|
||||||
|
|
||||||
|
function onChange(category) {
|
||||||
|
selectedCategory = category
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonProps = [
|
||||||
|
{ value: "desktop", text: "Desktop" },
|
||||||
|
{ value: "mobile", text: "Mobile" },
|
||||||
|
{ value: "hover", text: "Hover" },
|
||||||
|
{ value: "active", text: "Active" },
|
||||||
|
{ value: "selected", text: "Selected" },
|
||||||
|
]
|
||||||
|
|
||||||
|
$: propertyGroupNames =
|
||||||
|
!!panelDefinition.properties && Object.keys(panelDefinition.properties)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="design-view-container">
|
||||||
|
|
||||||
|
<div class="design-view-state-categories">
|
||||||
|
<FlatButtonGroup value={selectedCategory} {buttonProps} {onChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="design-view-property-groups">
|
||||||
|
{#each propertyGroupNames as groupName}
|
||||||
|
<PropertyGroup
|
||||||
|
name={groupName}
|
||||||
|
properties={getProperties(groupName)}
|
||||||
|
{onPropChanged}
|
||||||
|
{componentDefinition}
|
||||||
|
{componentInstance} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.design-view-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.design-view-state-categories {
|
||||||
|
flex: 0 0 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.design-view-property-groups {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<script>
|
||||||
|
export let value = ""
|
||||||
|
export let text = ""
|
||||||
|
export let icon = ""
|
||||||
|
export let onClick = value => {}
|
||||||
|
export let selected = false
|
||||||
|
|
||||||
|
$: useIcon = !!icon
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flatbutton" class:selected on:click={() => onClick(value || text)}>
|
||||||
|
{#if useIcon}
|
||||||
|
<i class={icon} />
|
||||||
|
{:else}
|
||||||
|
<span>{text}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.flatbutton {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
|
text-align: center;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #808192;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: Roboto;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.11px;
|
||||||
|
transition: background 0.5s, color 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background: #808192;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
|
import FlatButton from "./FlatButton.svelte"
|
||||||
|
export let buttonProps = []
|
||||||
|
export let isMultiSelect = false
|
||||||
|
export let value = []
|
||||||
|
export let initialValue = ""
|
||||||
|
export let onChange = selected => {}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!value && !!initialValue) {
|
||||||
|
value = initialValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function onButtonClicked(v) {
|
||||||
|
let val
|
||||||
|
if (isMultiSelect) {
|
||||||
|
if (value.includes(v)) {
|
||||||
|
let idx = value.findIndex(i => i === v)
|
||||||
|
val = [...value].splice(idx, 1)
|
||||||
|
} else {
|
||||||
|
val = [...value, v]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val = v
|
||||||
|
}
|
||||||
|
onChange(val)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flatbutton-group">
|
||||||
|
{#each buttonProps as props}
|
||||||
|
<div class="button-container">
|
||||||
|
<FlatButton
|
||||||
|
selected={value.includes(props.value)}
|
||||||
|
onClick={onButtonClicked}
|
||||||
|
{...props} />
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.flatbutton-group {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
flex: 1;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
export let value = ""
|
||||||
|
export let onChange = value => {}
|
||||||
|
export let options = []
|
||||||
|
export let initialValue = ""
|
||||||
|
export let styleBindingProperty = ""
|
||||||
|
|
||||||
|
$: bindOptionToStyle = !!styleBindingProperty
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!value && !!initialValue) {
|
||||||
|
value = initialValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<select
|
||||||
|
class="uk-select uk-form-small"
|
||||||
|
{value}
|
||||||
|
on:change={ev => onChange(ev.target.value)}>
|
||||||
|
{#each options as { value, label }}
|
||||||
|
{#if bindOptionToStyle}
|
||||||
|
<option
|
||||||
|
style={`${styleBindingProperty}: ${value || label};`}
|
||||||
|
value={value || label}>
|
||||||
|
{label}
|
||||||
|
</option>
|
||||||
|
{:else}
|
||||||
|
<option value={value || label}>{label}</option>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</select>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<script>
|
||||||
|
export let label = ""
|
||||||
|
export let control = null
|
||||||
|
export let value = ""
|
||||||
|
export let props = {}
|
||||||
|
export let onChange = () => {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="property-control">
|
||||||
|
<div class="label">{label}</div>
|
||||||
|
<div class="control">
|
||||||
|
<svelte:component
|
||||||
|
this={control}
|
||||||
|
{value}
|
||||||
|
on:change={onChange}
|
||||||
|
{onChange}
|
||||||
|
{...props} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.property-control {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
margin: 8px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
flex: 0 0 50px;
|
||||||
|
padding: 0px 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control {
|
||||||
|
flex: 1;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,101 @@
|
||||||
|
<script>
|
||||||
|
import { excludeProps } from "./propertyCategories.js"
|
||||||
|
import PropertyControl from "./PropertyControl.svelte"
|
||||||
|
|
||||||
|
export let name = ""
|
||||||
|
export let properties = {}
|
||||||
|
export let componentInstance = {}
|
||||||
|
export let componentDefinition = {}
|
||||||
|
export let onPropChanged = () => {}
|
||||||
|
|
||||||
|
export let show = false
|
||||||
|
let showComponentGroup = false
|
||||||
|
|
||||||
|
const propExistsOnComponentDef = prop => prop in componentDefinition.props
|
||||||
|
const capitalize = name => name[0].toUpperCase() + name.slice(1)
|
||||||
|
|
||||||
|
function onChange(key, v) {
|
||||||
|
!!v.target ? onPropChanged(key, v.target.value) : onPropChanged(key, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
let res = false
|
||||||
|
let componentProps = Object.keys(componentDefinition.props)
|
||||||
|
for (let prop in properties) {
|
||||||
|
if (componentProps.includes(prop)) {
|
||||||
|
showComponentGroup = true
|
||||||
|
}
|
||||||
|
if (showComponentGroup) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: propertyDefinition = Object.entries(properties)
|
||||||
|
$: icon = show ? "ri-arrow-down-s-fill" : "ri-arrow-right-s-fill"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- {#if showComponentGroup} -->
|
||||||
|
<div class="property-group-container">
|
||||||
|
<div class="property-group-name" on:click={() => (show = !show)}>
|
||||||
|
<div class="icon">
|
||||||
|
<i class={icon} />
|
||||||
|
</div>
|
||||||
|
<div class="name">{capitalize(name)}</div>
|
||||||
|
</div>
|
||||||
|
<div class="property-panel" class:show>
|
||||||
|
|
||||||
|
{#each propertyDefinition as [key, definition]}
|
||||||
|
<!-- {#if propExistsOnComponentDef(key)} -->
|
||||||
|
<PropertyControl
|
||||||
|
label={definition.label || capitalize(key)}
|
||||||
|
control={definition.control}
|
||||||
|
value={componentInstance[key]}
|
||||||
|
onChange={value => onChange(key, value)}
|
||||||
|
props={{ ...excludeProps(definition, ['control']) }} />
|
||||||
|
<!-- {/if} -->
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- {/if} -->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.property-group-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: auto;
|
||||||
|
background: #fbfbfb;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-group-name {
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 0 0 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
padding-top: 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.14px;
|
||||||
|
color: #393c44;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
flex: 0 0 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-panel {
|
||||||
|
height: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show {
|
||||||
|
overflow: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,240 @@
|
||||||
|
<script>
|
||||||
|
import ComponentsHierarchy from "./ComponentsHierarchy.svelte"
|
||||||
|
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte"
|
||||||
|
import PageLayout from "./PageLayout.svelte"
|
||||||
|
import PagesList from "./PagesList.svelte"
|
||||||
|
import { store } from "builderStore"
|
||||||
|
import IconButton from "components/common/IconButton.svelte"
|
||||||
|
import NewScreen from "./NewScreen.svelte"
|
||||||
|
import CurrentItemPreview from "./CurrentItemPreview.svelte"
|
||||||
|
import SettingsView from "./SettingsView.svelte"
|
||||||
|
import PageView from "./PageView.svelte"
|
||||||
|
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte"
|
||||||
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
import { last } from "lodash/fp"
|
||||||
|
import { AddIcon } from "components/common/Icons"
|
||||||
|
|
||||||
|
let newScreenPicker
|
||||||
|
let confirmDeleteDialog
|
||||||
|
let componentToDelete = ""
|
||||||
|
|
||||||
|
const newScreen = () => {
|
||||||
|
newScreenPicker.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
let settingsView
|
||||||
|
const settings = () => {
|
||||||
|
settingsView.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmDeleteComponent = component => {
|
||||||
|
componentToDelete = component
|
||||||
|
confirmDeleteDialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastPartOfName = c => (c ? last(c.split("/")) : "")
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="root">
|
||||||
|
|
||||||
|
<div class="ui-nav">
|
||||||
|
|
||||||
|
<div class="pages-list-container">
|
||||||
|
<div class="nav-header">
|
||||||
|
<span class="navigator-title">Navigator</span>
|
||||||
|
<div class="border-line" />
|
||||||
|
|
||||||
|
<span class="components-nav-page">Pages</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-items-container">
|
||||||
|
<PagesList />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-line" />
|
||||||
|
|
||||||
|
<PageLayout layout={$store.pages[$store.currentPageName]} />
|
||||||
|
|
||||||
|
<div class="border-line" />
|
||||||
|
|
||||||
|
<div class="components-list-container">
|
||||||
|
<div class="nav-group-header">
|
||||||
|
<span class="components-nav-header" style="margin-top: 0;">
|
||||||
|
Screens
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
<button on:click={newScreen}>
|
||||||
|
<AddIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-items-container">
|
||||||
|
<ComponentsHierarchy screens={$store.screens} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview-pane">
|
||||||
|
<CurrentItemPreview />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if $store.currentFrontEndType === 'screen' || $store.currentFrontEndType === 'page'}
|
||||||
|
<div class="components-pane">
|
||||||
|
<ComponentsPaneSwitcher />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NewScreen bind:this={newScreenPicker} />
|
||||||
|
<SettingsView bind:this={settingsView} />
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:this={confirmDeleteDialog}
|
||||||
|
title="Confirm Delete"
|
||||||
|
body={`Are you sure you wish to delete this '${lastPartOfName(componentToDelete)}' component`}
|
||||||
|
okText="Delete Component"
|
||||||
|
onOk={() => store.deleteComponent(componentToDelete)} />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 275px 1fr 300px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1800px) {
|
||||||
|
.root {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 300px 1fr 300px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-nav {
|
||||||
|
grid-column: 1;
|
||||||
|
background-color: var(--white);
|
||||||
|
height: calc(100vh - 49px);
|
||||||
|
padding: 0;
|
||||||
|
overflow: scroll;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-pane {
|
||||||
|
grid-column: 2;
|
||||||
|
margin: 40px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0px 6px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-pane {
|
||||||
|
grid-column: 3;
|
||||||
|
background-color: var(--white);
|
||||||
|
height: 100vh;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-nav-page {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #000333;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding-left: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
opacity: 0.4;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-nav-header {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #000333;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
opacity: 0.4;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-items-container {
|
||||||
|
padding: 1rem 0rem 0rem 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-header {
|
||||||
|
display: flex;
|
||||||
|
padding: 0px 20px 0px 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: bold;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-header > div:nth-child(1) {
|
||||||
|
padding: 0rem 0.5rem 0rem 0rem;
|
||||||
|
vertical-align: bottom;
|
||||||
|
grid-column-start: icon;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-header > span:nth-child(3) {
|
||||||
|
margin-left: 5px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
grid-column-start: title;
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-header > div:nth-child(3) {
|
||||||
|
vertical-align: bottom;
|
||||||
|
grid-column-start: button;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--primary75);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-header > div:nth-child(3):hover {
|
||||||
|
color: var(--primary75);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigator-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--secondary100);
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
line-height: 1rem !important;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-line {
|
||||||
|
border-bottom: 1px solid #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-list-container {
|
||||||
|
padding: 20px 0px 0 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,177 @@
|
||||||
|
import Input from "../common/Input.svelte"
|
||||||
|
import OptionSelect from "./OptionSelect.svelte"
|
||||||
|
/*
|
||||||
|
TODO: Allow for default values for all properties
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const general = {
|
||||||
|
text: { control: Input },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const layout = {
|
||||||
|
flexDirection: {
|
||||||
|
label: "Direction",
|
||||||
|
control: OptionSelect,
|
||||||
|
initialValue: "columnReverse",
|
||||||
|
options: [
|
||||||
|
{ label: "row" },
|
||||||
|
{ label: "row-reverse", value: "rowReverse" },
|
||||||
|
{ label: "column" },
|
||||||
|
{ label: "column-reverse", value: "columnReverse" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
justifyContent: { label: "Justify", control: Input },
|
||||||
|
alignItems: { label: "Align", control: Input },
|
||||||
|
flexWrap: {
|
||||||
|
label: "Wrap",
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [{ label: "wrap" }, { label: "no wrap", value: "noWrap" }],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const spacing = {
|
||||||
|
padding: { control: Input },
|
||||||
|
margin: { control: Input },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const size = {
|
||||||
|
width: { control: Input },
|
||||||
|
height: { control: Input },
|
||||||
|
minWidth: { label: "Min W", control: Input },
|
||||||
|
minHeight: { label: "Min H", control: Input },
|
||||||
|
maxWidth: { label: "Max W", control: Input },
|
||||||
|
maxHeight: { label: "Max H", control: Input },
|
||||||
|
overflow: {
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "visible" },
|
||||||
|
{ label: "auto" },
|
||||||
|
{ label: "hidden" },
|
||||||
|
{ label: "auto" },
|
||||||
|
{ label: "scroll" },
|
||||||
|
],
|
||||||
|
}, //custom
|
||||||
|
}
|
||||||
|
|
||||||
|
export const position = {
|
||||||
|
position: {
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "static" },
|
||||||
|
{ label: "relative" },
|
||||||
|
{ label: "fixed" },
|
||||||
|
{ label: "absolute" },
|
||||||
|
{ label: "sticky" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const typography = {
|
||||||
|
fontFamily: {
|
||||||
|
label: "Font",
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "initial" },
|
||||||
|
{ label: "Times New Roman" },
|
||||||
|
{ label: "Georgia" },
|
||||||
|
{ label: "Arial" },
|
||||||
|
{ label: "Arial Black" },
|
||||||
|
{ label: "Comic Sans MS" },
|
||||||
|
{ label: "Impact" },
|
||||||
|
{ label: "Lucida Sans Unicode" },
|
||||||
|
],
|
||||||
|
styleBindingProperty: "font-family",
|
||||||
|
},
|
||||||
|
fontWeight: {
|
||||||
|
label: "weight",
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "normal" },
|
||||||
|
{ label: "bold" },
|
||||||
|
{ label: "bolder" },
|
||||||
|
{ label: "lighter" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fontSize: { label: "size", control: Input },
|
||||||
|
lineHeight: { label: "Line H", control: Input },
|
||||||
|
color: {
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "black" },
|
||||||
|
{ label: "red" },
|
||||||
|
{ label: "white" },
|
||||||
|
{ label: "blue" },
|
||||||
|
{ label: "green" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
textAlign: {
|
||||||
|
label: "align",
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "initial" },
|
||||||
|
{ label: "left" },
|
||||||
|
{ label: "right" },
|
||||||
|
{ label: "center" },
|
||||||
|
{ label: "justify" },
|
||||||
|
],
|
||||||
|
}, //custom
|
||||||
|
textTransform: { label: "transform", control: Input }, //custom
|
||||||
|
fontStyle: { label: "style", control: Input }, //custom
|
||||||
|
}
|
||||||
|
|
||||||
|
export const background = {
|
||||||
|
backgroundColor: {
|
||||||
|
label: "Background Color",
|
||||||
|
control: OptionSelect,
|
||||||
|
options: [
|
||||||
|
{ label: "white" },
|
||||||
|
{ label: "red" },
|
||||||
|
{ label: "blue" },
|
||||||
|
{ label: "green" },
|
||||||
|
{ label: "black" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
image: { control: Input }, //custom
|
||||||
|
}
|
||||||
|
|
||||||
|
export const border = {
|
||||||
|
borderRadius: { label: "radius", control: Input },
|
||||||
|
borderWidth: { label: "width", control: Input }, //custom
|
||||||
|
borderColor: { label: "color", control: Input },
|
||||||
|
borderStyle: { label: "style", control: Input },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const effects = {
|
||||||
|
opacity: { control: Input },
|
||||||
|
rotate: { control: Input },
|
||||||
|
shadow: { control: Input },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const transitions = {
|
||||||
|
property: { control: Input },
|
||||||
|
duration: { control: Input },
|
||||||
|
ease: { control: Input },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const all = {
|
||||||
|
general,
|
||||||
|
layout,
|
||||||
|
spacing,
|
||||||
|
size,
|
||||||
|
position,
|
||||||
|
typography,
|
||||||
|
background,
|
||||||
|
border,
|
||||||
|
effects,
|
||||||
|
transitions,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function excludeProps(props, propsToExclude) {
|
||||||
|
const modifiedProps = {}
|
||||||
|
for (const prop in props) {
|
||||||
|
if (!propsToExclude.includes(prop)) {
|
||||||
|
modifiedProps[prop] = props[prop]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modifiedProps
|
||||||
|
}
|
|
@ -1,3 +1,13 @@
|
||||||
|
import {
|
||||||
|
general,
|
||||||
|
layout,
|
||||||
|
typography,
|
||||||
|
border,
|
||||||
|
size,
|
||||||
|
background,
|
||||||
|
all,
|
||||||
|
} from "./propertyCategories.js"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
categories: [
|
categories: [
|
||||||
{
|
{
|
||||||
|
@ -20,6 +30,7 @@ export default {
|
||||||
icon: "ri-layout-row-fill",
|
icon: "ri-layout-row-fill",
|
||||||
commonProps: {},
|
commonProps: {},
|
||||||
children: [],
|
children: [],
|
||||||
|
properties: { background, size },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Text",
|
name: "Text",
|
||||||
|
@ -32,23 +43,18 @@ export default {
|
||||||
name: "Headline",
|
name: "Headline",
|
||||||
description: "A component for displaying heading text",
|
description: "A component for displaying heading text",
|
||||||
icon: "ri-heading",
|
icon: "ri-heading",
|
||||||
props: {
|
properties: {
|
||||||
type: {
|
...all
|
||||||
type: "options",
|
|
||||||
options: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
||||||
default: "h1",
|
|
||||||
},
|
|
||||||
text: "string",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/text",
|
_component: "@budibase/standard-components/text",
|
||||||
name: "Paragraph",
|
name: "Paragraph",
|
||||||
description: "A component for displaying paragraph text.",
|
description: "A component for displaying paragraph text.",
|
||||||
icon: "ri-paragraph",
|
icon: 'ri-paragraph',
|
||||||
props: {},
|
properties: { general, typography },
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Input",
|
name: "Input",
|
||||||
|
@ -59,60 +65,58 @@ export default {
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/input",
|
_component: "@budibase/standard-components/input",
|
||||||
name: "Textfield",
|
name: "Textfield",
|
||||||
description:
|
description: "A textfield component that allows the user to input text.",
|
||||||
"A textfield component that allows the user to input text.",
|
icon: 'ri-edit-box-line',
|
||||||
icon: "ri-edit-box-line",
|
properties: {}
|
||||||
props: {},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/checkbox",
|
_component: "@budibase/standard-components/checkbox",
|
||||||
name: "Checkbox",
|
name: "Checkbox",
|
||||||
description: "A selectable checkbox component",
|
description: "A selectable checkbox component",
|
||||||
icon: "ri-checkbox-line",
|
icon: 'ri-checkbox-line',
|
||||||
props: {},
|
properties: {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/radiobutton",
|
_component: "@budibase/standard-components/radiobutton",
|
||||||
name: "Radiobutton",
|
name: "Radiobutton",
|
||||||
description: "A selectable radiobutton component",
|
description: "A selectable radiobutton component",
|
||||||
icon: "ri-radio-button-line",
|
icon: 'ri-radio-button-line',
|
||||||
props: {},
|
properties: {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/select",
|
_component: "@budibase/standard-components/select",
|
||||||
name: "Select",
|
name: "Select",
|
||||||
description:
|
description: "A select component for choosing from different options",
|
||||||
"A select component for choosing from different options",
|
icon: 'ri-file-list-line',
|
||||||
icon: "ri-file-list-line",
|
properties: {}
|
||||||
props: {},
|
}
|
||||||
},
|
]
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/button",
|
_component: "@budibase/standard-components/button",
|
||||||
name: "Button",
|
name: 'Button',
|
||||||
description: "A basic html button that is ready for styling",
|
description: 'A basic html button that is ready for styling',
|
||||||
icon: "ri-radio-button-fill",
|
icon: 'ri-radio-button-fill',
|
||||||
commonProps: {},
|
|
||||||
children: [],
|
children: [],
|
||||||
|
properties: { background, typography, border, size },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/icon",
|
_component: "@budibase/standard-components/icon",
|
||||||
name: "Icon",
|
name: 'Icon',
|
||||||
description: "A basic component for displaying icons",
|
description: 'A basic component for displaying icons',
|
||||||
icon: "ri-sun-fill",
|
icon: 'ri-sun-fill',
|
||||||
commonProps: {},
|
properties: {},
|
||||||
children: [],
|
children: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/link",
|
_component: "@budibase/standard-components/link",
|
||||||
name: "Link",
|
name: 'Link',
|
||||||
description: "A basic link component for internal and external links",
|
description: 'A basic link component for internal and external links',
|
||||||
icon: "ri-link",
|
icon: 'ri-link',
|
||||||
commonProps: {},
|
properties: {},
|
||||||
children: [],
|
children: []
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Blocks",
|
name: "Blocks",
|
||||||
|
@ -120,21 +124,18 @@ export default {
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
_component: "@budibase/materialdesign-components/BasicCard",
|
_component: "@budibase/materialdesign-components/BasicCard",
|
||||||
name: "Card",
|
name: 'Card',
|
||||||
description:
|
description: 'A basic card component that can contain content and actions.',
|
||||||
"A basic card component that can contain content and actions.",
|
icon: 'ri-layout-bottom-line',
|
||||||
icon: "ri-layout-bottom-line",
|
|
||||||
commonProps: {},
|
|
||||||
children: [],
|
children: [],
|
||||||
|
properties: { size, background, border },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/login",
|
name: 'Login',
|
||||||
name: "Login",
|
description: 'A component that automatically generates a login screen for your app.',
|
||||||
description:
|
icon: 'ri-login-box-fill',
|
||||||
"A component that automatically generates a login screen for your app.",
|
properties: {},
|
||||||
icon: "ri-login-box-fill",
|
children: []
|
||||||
commonProps: {},
|
|
||||||
children: [],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Navigation Bar",
|
name: "Navigation Bar",
|
||||||
|
@ -142,30 +143,28 @@ export default {
|
||||||
description:
|
description:
|
||||||
"A component for handling the navigation within your app.",
|
"A component for handling the navigation within your app.",
|
||||||
icon: "ri-navigation-fill",
|
icon: "ri-navigation-fill",
|
||||||
commonProps: {},
|
properties: {},
|
||||||
children: [],
|
children: []
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Data",
|
name: "Data",
|
||||||
isCategory: true,
|
isCategory: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
name: "Table",
|
name: 'Table',
|
||||||
_component: "@budibase/materialdesign-components/Datatable",
|
description: 'A component that generates a table from your data.',
|
||||||
description: "A component that generates a table from your data.",
|
icon: 'ri-archive-drawer-fill',
|
||||||
icon: "ri-archive-drawer-fill",
|
properties: {},
|
||||||
commonProps: {},
|
children: []
|
||||||
children: [],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: 'Form',
|
||||||
|
description: 'A component that generates a form from your data.',
|
||||||
|
icon: 'ri-file-edit-fill',
|
||||||
|
properties: {},
|
||||||
_component: "@budibase/materialdesign-components/Form",
|
_component: "@budibase/materialdesign-components/Form",
|
||||||
name: "Form",
|
|
||||||
description: "A component that generates a form from your data.",
|
|
||||||
icon: "ri-file-edit-fill",
|
|
||||||
commonProps: {},
|
|
||||||
component: "@budibase/materialdesign-components/Form",
|
|
||||||
template: {
|
template: {
|
||||||
component: "@budibase/materialdesign-components/Form",
|
component: "@budibase/materialdesign-components/Form",
|
||||||
description: "Form for saving a record",
|
description: "Form for saving a record",
|
||||||
|
|
|
@ -386,6 +386,8 @@
|
||||||
},
|
},
|
||||||
"backgroundColor": "string",
|
"backgroundColor": "string",
|
||||||
"color": "string",
|
"color": "string",
|
||||||
|
"height": "string",
|
||||||
|
"width": "string",
|
||||||
"borderWidth": "string",
|
"borderWidth": "string",
|
||||||
"borderColor": "string",
|
"borderColor": "string",
|
||||||
"borderStyle": {
|
"borderStyle": {
|
||||||
|
@ -403,7 +405,7 @@
|
||||||
],
|
],
|
||||||
"default": "none"
|
"default": "none"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"container": true,
|
"container": true,
|
||||||
"tags": [
|
"tags": [
|
||||||
"div",
|
"div",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import { buildStyle } from "./buildStyle"
|
import { buildStyle } from "./buildStyle"
|
||||||
export let className = "default"
|
export let className = "default"
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let contentText
|
export let text
|
||||||
export let onClick
|
export let onClick
|
||||||
export let background
|
export let background
|
||||||
export let color
|
export let color
|
||||||
|
@ -66,9 +66,7 @@
|
||||||
disabled={disabled || false}
|
disabled={disabled || false}
|
||||||
on:click={clickHandler}
|
on:click={clickHandler}
|
||||||
style={buttonStyles}>
|
style={buttonStyles}>
|
||||||
{#if !_bb.props._children || _bb.props._children.length === 0}
|
{#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if}
|
||||||
{contentText}
|
|
||||||
{/if}
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
export let type = "div"
|
export let type = "div"
|
||||||
export let backgroundColor
|
export let backgroundColor
|
||||||
export let color
|
export let color
|
||||||
|
export let width
|
||||||
|
export let height
|
||||||
export let borderWidth
|
export let borderWidth
|
||||||
export let borderColor
|
export let borderColor
|
||||||
export let borderStyle
|
export let borderStyle
|
||||||
|
@ -18,6 +20,8 @@
|
||||||
$: cssVariables = {
|
$: cssVariables = {
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
color,
|
color,
|
||||||
|
height,
|
||||||
|
width,
|
||||||
borderWidth,
|
borderWidth,
|
||||||
borderColor,
|
borderColor,
|
||||||
borderStyle,
|
borderStyle,
|
||||||
|
@ -108,6 +112,14 @@
|
||||||
color: var(--color);
|
color: var(--color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.height {
|
||||||
|
height: var(--height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.width {
|
||||||
|
width: var(--width);
|
||||||
|
}
|
||||||
|
|
||||||
.borderColor {
|
.borderColor {
|
||||||
border-color: var(--borderColor);
|
border-color: var(--borderColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
$: containerElement && !text && _bb.attachChildren(containerElement)
|
$: containerElement && !text && _bb.attachChildren(containerElement)
|
||||||
$: style = buildStyle({ "font-family": fontFamily, color })
|
$: style = buildStyle({ "font-family": fontFamily, color })
|
||||||
// $: console.log("HEADING", color)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if type === 'h1'}
|
{#if type === 'h1'}
|
||||||
|
|
Loading…
Reference in New Issue