Merge branch 'test/property-panel-changes' into test/master-and-property-panel

This commit is contained in:
Conor_Mack 2020-05-18 12:15:03 +01:00
commit 38b57f3024
20 changed files with 964 additions and 263 deletions

View File

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

View File

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

View File

@ -35,10 +35,10 @@
styles = styles styles = styles
} }
$: stylesheetLinks = pipe($store.pages.stylesheets, [ $: stylesheetLinks = pipe(
map(s => `<link rel="stylesheet" href="${s}"/>`), $store.pages.stylesheets,
join("\n"), [map(s => `<link rel="stylesheet" href="${s}"/>`), join("\n")]
]) )
$: screensExist = $: screensExist =
$store.currentPreviewItem._screens && $store.currentPreviewItem._screens &&

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

View File

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

View File

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

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 { 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",

View File

@ -12,10 +12,10 @@
"props": { "props": {
"logoUrl": "string", "logoUrl": "string",
"title": "string", "title": "string",
"backgroundColor": "colour", "backgroundColor": "string",
"color": "colour", "color": "string",
"borderWidth": "string", "borderWidth": "string",
"borderColor": "colour", "borderColor": "string",
"borderStyle": "string" "borderStyle": "string"
} }
}, },
@ -30,8 +30,8 @@
"className": "string", "className": "string",
"disabled": "bool", "disabled": "bool",
"onClick": "event", "onClick": "event",
"background": "colour", "background": "string",
"color": "colour", "color": "string",
"border": "string", "border": "string",
"padding": "string", "padding": "string",
"hoverColor": "string", "hoverColor": "string",
@ -167,7 +167,7 @@
"children": false, "children": false,
"props": { "props": {
"text": "string", "text": "string",
"color": "colour", "color": "string",
"fontFamily": { "fontFamily": {
"type": "options", "type": "options",
"default": "initial", "default": "initial",
@ -259,7 +259,7 @@
"props": { "props": {
"icon": "string", "icon": "string",
"fontSize": "string", "fontSize": "string",
"color": "colour" "color": "string"
} }
}, },
"datatable": { "datatable": {
@ -328,8 +328,8 @@
"url": "string", "url": "string",
"openInNewTab": "bool", "openInNewTab": "bool",
"text": "string", "text": "string",
"color": "colour", "color": "string",
"hoverColor": "colour", "hoverColor": "string",
"underline": "bool", "underline": "bool",
"fontSize": "string", "fontSize": "string",
"fontFamily": { "fontFamily": {
@ -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",
@ -416,7 +418,6 @@
"description": "An HTML H1 - H6 tag", "description": "An HTML H1 - H6 tag",
"props": { "props": {
"className": "string", "className": "string",
"color":"colour",
"text": "string", "text": "string",
"type": { "type": {
"type": "options", "type": "options",

View File

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

View File

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

View File

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