Merge branch 'property-panel/structure' into property-panel/new-backend

This commit is contained in:
Conor_Mack 2020-05-12 14:53:20 +01:00
commit dc21bcd525
19 changed files with 951 additions and 249 deletions

View File

@ -2,7 +2,7 @@
import { onMount, beforeUpdate, afterUpdate } from "svelte"
export let value = null
export let onChanged = () => {}
export let onChange = () => {}
export let swatches = []
let picker
@ -58,13 +58,10 @@
onMount(() => {
getRecentColors()
createPicker()
picker.on("save", (colour, instance) => {
let color = colour.toHEXA().toString()
onChanged(color)
setRecentColor(color)
picker.hide()
})
return () => {
picker.destroyAndRemove()
picker = null
}
})
</script>

View File

@ -1,8 +1,11 @@
<script>
export let value = ""
export let width = ""
let style = { width }
</script>
<input type="text" on:change bind:value />
<input type="text" style={`width: ${width};`} on:change bind:value />
<style>
input {

View File

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

View File

@ -13,23 +13,60 @@
import LayoutEditor from "./LayoutEditor.svelte"
import EventsEditor from "./EventsEditor"
let current_view = "props"
let codeEditor
import panelStructure from "./temporaryPanelStructure.js"
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
$: 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 =
$store.currentFrontEndType === "page"
? getProps($store.currentPreviewItem, ["name", "favicon"])
: getProps($store.currentPreviewItem, ["name", "description", "route"])
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) {
return keys.map((key, i) => [key, obj[key], obj.props._id + i])
@ -37,116 +74,31 @@
</script>
<div class="root">
<ul>
<li>
<button
class:selected={current_view === 'props'}
on:click={() => (current_view = 'props')}>
<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>
<CategoryTab
onClick={category => (selectedCategory = category)}
{categories}
{selectedCategory} />
<div class="component-props-container">
{#if current_view === 'props'}
{#if $store.currentView === 'detail'}
{#each screen_props as [k, v, id] (id)}
<div class="detail-prop" for={k}>
<label>{k}:</label>
<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 current_view === 'design'}
<DesignView
{panelDefinition}
{componentInstance}
{componentDefinition}
{onPropChanged} />
{/if}
<CodeEditor
bind:this={codeEditor}
code={component._code}
onCodeChanged={store.setComponentCode} />
</div>
</div>
<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 {
height: 100%;
padding: 20px;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
.title > div:nth-child(1) {
@ -162,52 +114,4 @@
margin-top: 10px;
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>

View File

@ -2,6 +2,7 @@
import { splitName } from "./pagesParsing/splitRootComponentName.js"
import components from "./temporaryPanelStructure.js"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import CategoryTab from "./CategoryTab.svelte"
import {
find,
sortBy,
@ -36,15 +37,12 @@
</script>
<div class="root">
<ul class="tabs">
{#each categories as category}
<li
on:click={() => (selectedCategory = category)}
class:active={selectedCategory === category}>
{category.name}
</li>
{/each}
</ul>
<CategoryTab
onClick={category => (selectedCategory = category)}
{selectedCategory}
{categories} />
<div class="panel">
<Tab
list={selectedCategory}

View File

@ -24,13 +24,13 @@
<button
class:selected={selected === COMPONENT_SELECTION_TAB}
on:click={() => selectTab(COMPONENT_SELECTION_TAB)}>
Components
Add
</button>
<button
class:selected={selected === PROPERTIES_TAB}
on:click={() => selectTab(PROPERTIES_TAB)}>
Properties
Edit
</button>
</div>
@ -55,6 +55,7 @@
display: flex;
flex-direction: column;
padding: 20px 0;
border-left: solid 1px #e8e8ef;
}
.switcher {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,13 @@
import {
general,
layout,
typography,
border,
size,
background,
all,
} from "./propertyCategories.js"
export default {
categories: [
{
@ -20,6 +30,7 @@ export default {
icon: "ri-layout-row-fill",
commonProps: {},
children: [],
properties: { background, size },
},
{
name: "Text",
@ -32,23 +43,18 @@ export default {
name: "Headline",
description: "A component for displaying heading text",
icon: "ri-heading",
props: {
type: {
type: "options",
options: ["h1", "h2", "h3", "h4", "h5", "h6"],
default: "h1",
},
text: "string",
properties: {
...all
},
},
{
_component: "@budibase/standard-components/text",
name: "Paragraph",
description: "A component for displaying paragraph text.",
icon: "ri-paragraph",
props: {},
},
],
icon: 'ri-paragraph',
properties: { general, typography },
}
]
},
{
name: "Input",
@ -59,60 +65,58 @@ export default {
{
_component: "@budibase/standard-components/input",
name: "Textfield",
description:
"A textfield component that allows the user to input text.",
icon: "ri-edit-box-line",
props: {},
description: "A textfield component that allows the user to input text.",
icon: 'ri-edit-box-line',
properties: {}
},
{
_component: "@budibase/standard-components/checkbox",
name: "Checkbox",
description: "A selectable checkbox component",
icon: "ri-checkbox-line",
props: {},
icon: 'ri-checkbox-line',
properties: {}
},
{
_component: "@budibase/standard-components/radiobutton",
name: "Radiobutton",
description: "A selectable radiobutton component",
icon: "ri-radio-button-line",
props: {},
icon: 'ri-radio-button-line',
properties: {}
},
{
_component: "@budibase/standard-components/select",
name: "Select",
description:
"A select component for choosing from different options",
icon: "ri-file-list-line",
props: {},
},
],
description: "A select component for choosing from different options",
icon: 'ri-file-list-line',
properties: {}
}
]
},
{
_component: "@budibase/standard-components/button",
name: "Button",
description: "A basic html button that is ready for styling",
icon: "ri-radio-button-fill",
commonProps: {},
name: 'Button',
description: 'A basic html button that is ready for styling',
icon: 'ri-radio-button-fill',
children: [],
properties: { background, typography, border, size },
},
{
_component: "@budibase/standard-components/icon",
name: "Icon",
description: "A basic component for displaying icons",
icon: "ri-sun-fill",
commonProps: {},
children: [],
name: 'Icon',
description: 'A basic component for displaying icons',
icon: 'ri-sun-fill',
properties: {},
children: []
},
{
_component: "@budibase/standard-components/link",
name: "Link",
description: "A basic link component for internal and external links",
icon: "ri-link",
commonProps: {},
children: [],
},
],
name: 'Link',
description: 'A basic link component for internal and external links',
icon: 'ri-link',
properties: {},
children: []
}
]
},
{
name: "Blocks",
@ -120,21 +124,18 @@ export default {
children: [
{
_component: "@budibase/materialdesign-components/BasicCard",
name: "Card",
description:
"A basic card component that can contain content and actions.",
icon: "ri-layout-bottom-line",
commonProps: {},
name: 'Card',
description: 'A basic card component that can contain content and actions.',
icon: 'ri-layout-bottom-line',
children: [],
properties: { size, background, border },
},
{
_component: "@budibase/standard-components/login",
name: "Login",
description:
"A component that automatically generates a login screen for your app.",
icon: "ri-login-box-fill",
commonProps: {},
children: [],
name: 'Login',
description: 'A component that automatically generates a login screen for your app.',
icon: 'ri-login-box-fill',
properties: {},
children: []
},
{
name: "Navigation Bar",
@ -142,30 +143,28 @@ export default {
description:
"A component for handling the navigation within your app.",
icon: "ri-navigation-fill",
commonProps: {},
children: [],
},
],
properties: {},
children: []
}
]
},
{
name: "Data",
isCategory: true,
children: [
{
name: "Table",
_component: "@budibase/materialdesign-components/Datatable",
description: "A component that generates a table from your data.",
icon: "ri-archive-drawer-fill",
commonProps: {},
children: [],
name: 'Table',
description: 'A component that generates a table from your data.',
icon: 'ri-archive-drawer-fill',
properties: {},
children: []
},
{
name: 'Form',
description: 'A component that generates a form from your data.',
icon: 'ri-file-edit-fill',
properties: {},
_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: {
component: "@budibase/materialdesign-components/Form",
description: "Form for saving a record",

View File

@ -386,6 +386,8 @@
},
"backgroundColor": "string",
"color": "string",
"height": "string",
"width": "string",
"borderWidth": "string",
"borderColor": "string",
"borderStyle": {
@ -403,7 +405,7 @@
],
"default": "none"
}
},
},
"container": true,
"tags": [
"div",

View File

@ -3,7 +3,7 @@
import { buildStyle } from "./buildStyle"
export let className = "default"
export let disabled = false
export let contentText
export let text
export let onClick
export let background
export let color
@ -66,9 +66,7 @@
disabled={disabled || false}
on:click={clickHandler}
style={buttonStyles}>
{#if !_bb.props._children || _bb.props._children.length === 0}
{contentText}
{/if}
{#if !_bb.props._children || _bb.props._children.length === 0}{text}{/if}
</button>
<style>

View File

@ -6,6 +6,8 @@
export let type = "div"
export let backgroundColor
export let color
export let width
export let height
export let borderWidth
export let borderColor
export let borderStyle
@ -18,6 +20,8 @@
$: cssVariables = {
backgroundColor,
color,
height,
width,
borderWidth,
borderColor,
borderStyle,
@ -108,6 +112,14 @@
color: var(--color);
}
.height {
height: var(--height);
}
.width {
width: var(--width);
}
.borderColor {
border-color: var(--borderColor);
}

View File

@ -11,7 +11,6 @@
$: containerElement && !text && _bb.attachChildren(containerElement)
$: style = buildStyle({ "font-family": fontFamily, color })
// $: console.log("HEADING", color)
</script>
{#if type === 'h1'}