Merge pull request #286 from Budibase/property-panel/components-from-design

Property panel components upgrade
This commit is contained in:
Conor_Mack 2020-06-02 11:22:52 +01:00 committed by GitHub
commit b977cbd9aa
18 changed files with 600 additions and 192 deletions

View File

@ -1,5 +1,3 @@
import { toNumber } from "lodash/fp"
export const generate_screen_css = component_arr => { export const generate_screen_css = component_arr => {
let styles = "" let styles = ""
for (const { _styles, _id, _children, _component } of component_arr) { for (const { _styles, _id, _children, _component } of component_arr) {
@ -19,16 +17,13 @@ export const generate_screen_css = component_arr => {
export const generate_css = style => { export const generate_css = style => {
let cssString = Object.entries(style).reduce((str, [key, value]) => { let cssString = Object.entries(style).reduce((str, [key, value]) => {
//TODO Handle arrays and objects here also
if (typeof value === "string") { if (typeof value === "string") {
if (value) { if (value) {
return (str += `${key}: ${value};\n`) return (str += `${key}: ${value};\n`)
} }
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
if (value.length > 0 && !value.every(v => v === "")) { if (value.length > 0 && !value.every(v => v === "")) {
return (str += `${key}: ${value return (str += `${key}: ${value.join(" ")};\n`)
.map(generate_array_styles)
.join(" ")};\n`)
} }
} }
}, "") }, "")
@ -36,16 +31,6 @@ export const generate_css = style => {
return (cssString || "").trim() return (cssString || "").trim()
} }
export const generate_array_styles = item => {
let safeItem = item === "" ? 0 : item
let hasPx = new RegExp("px$")
if (!hasPx.test(safeItem) && !isNaN(toNumber(safeItem))) {
return `${safeItem}px`
} else {
return safeItem
}
}
export const apply_class = (id, name = "element", styles, selector) => { export const apply_class = (id, name = "element", styles, selector) => {
if (selector === "normal") { if (selector === "normal") {
return `.${name}-${id} {\n${styles}\n}` return `.${name}-${id} {\n${styles}\n}`

View File

@ -364,6 +364,7 @@ const addChildComponent = store => (componentToAdd, presetName) => {
/** /**
* @param {string} props - props to add, as child of current component * @param {string} props - props to add, as child of current component
*/ */
const addTemplatedComponent = store => props => { const addTemplatedComponent = store => props => {
store.update(state => { store.update(state => {
walkProps(props, p => { walkProps(props, p => {

View File

@ -1,29 +1,42 @@
<script> <script>
import {onMount} from "svelte"
import { buildStyle } from "../../helpers.js"
export let value = "" export let value = ""
export let width = "" export let textAlign = "left"
export let width = "160px"
export let placeholder = ""
let style = { width } let centerPlaceholder = textAlign === "center"
let style = buildStyle({ width, textAlign })
</script> </script>
<input type="text" style={`width: ${width};`} on:change bind:value /> <input class:centerPlaceholder type="text" {placeholder} {style} on:change bind:value />
<style> <style>
input { input {
display: block; /* width: 32px; */
font-size: 14px;
font-weight: 500;
color: var(--ink);
line-height: 1.3;
padding: 12px;
width: 164px;
max-width: 100%;
box-sizing: border-box;
margin: 0;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background: #fff;
border: 1px solid var(--grey-dark);
height: 32px; height: 32px;
font-size: 12px;
font-weight: 700;
margin: 0px 0px 0px 1px;
color: var(--ink);
opacity: 0.7;
padding: 0px 4px;
line-height: 1.3;
/* padding: 12px; */
width: 164px;
box-sizing: border-box;
border: 1px solid var(--grey);
border-radius: 2px;
outline: none;
}
input::placeholder {
text-align: left;
}
.centerPlaceholder::placeholder {
text-align: center;
} }
</style> </style>

View File

@ -1,27 +1,35 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import Input from "../Input.svelte"
export let meta = [] export let meta = []
export let label = "" export let label = ""
export let value = [0, 0, 0, 0] export let value = ["0", "0", "0", "0"]
export let type = "text" export let suffix = ""
export let onChange = () => {} export let onChange = () => {}
function handleChange(val, idx) { function handleChange(val, idx) {
value.splice(idx, 1, val) value.splice(idx, 1, suffix ? val + suffix : val)
value = value value = value
onChange(value) let _value = value.map(v => (!v.endsWith(suffix) ? v + suffix : v))
onChange(_value)
} }
$: displayValues = value
? value.map(v => v.replace(new RegExp(`${suffix}$`), ""))
: []
</script> </script>
<div class="input-container"> <div class="input-container">
<div class="label">{label}</div> <div class="label">{label}</div>
<div class="inputs"> <div class="inputs-group">
{#each meta as { placeholder }, i} {#each meta as m, i}
<input <Input
{type} width="32px"
placeholder={placeholder || ''} textAlign="center"
value={!value || value[i] === 0 ? '' : value[i]} placeholder={m.placeholder || ''}
value={!displayValues || displayValues[i] === '0' ? '' : displayValues[i]}
on:change={e => handleChange(e.target.value || 0, i)} /> on:change={e => handleChange(e.target.value || 0, i)} />
{/each} {/each}
</div> </div>
@ -32,39 +40,8 @@
flex: 0; flex: 0;
} }
.inputs { .inputs-group {
flex: 1; flex: 1;
} }
input {
width: 40px;
height: 32px;
font-size: 12px;
font-weight: 700;
margin: 0px 0px 0px 1px;
text-align: center;
color: var(--ink);
opacity: 0.7;
padding: 0px 4px;
box-sizing: border-box;
border: 1px solid var(--grey);
border-radius: 2px;
outline: none;
}
input[type="text"]::-webkit-inner-spin-button,
input[type="text"]::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
}
input[type="text"] {
-moz-appearance: textfield;
}
input::placeholder {
text-align: center;
}
</style> </style>

View File

@ -106,10 +106,12 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/* Merge Check */
overflow-x: hidden; overflow-x: hidden;
overflow-y: hidden; overflow-y: hidden;
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
/* Merge Check */
} }
.title > div:nth-child(1) { .title > div:nth-child(1) {

View File

@ -54,7 +54,7 @@
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 20px 20px; padding: 20px 5px 20px 10px;
border-left: solid 1px var(--grey); border-left: solid 1px var(--grey);
} }
@ -78,4 +78,8 @@
.switcher > .selected { .switcher > .selected {
color: var(--ink); color: var(--ink);
} }
.panel {
height: 100%;
}
</style> </style>

View File

@ -55,6 +55,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%;
} }
.design-view-state-categories { .design-view-state-categories {
@ -63,6 +64,9 @@
.design-view-property-groups { .design-view-property-groups {
flex: 1; flex: 1;
overflow-y: auto;
overflow-x: hidden;
max-height: 500px;
} }
.no-design { .no-design {

View File

@ -1,21 +1,26 @@
<script> <script>
import {buildStyle} from "../../helpers.js"
export let value = "" export let value = ""
export let text = "" export let text = ""
export let icon = "" export let icon = ""
export let padding = "8px 5px;"
export let onClick = value => {} export let onClick = value => {}
export let selected = false export let selected = false
export let fontWeight = ""
$: style = buildStyle({padding, fontWeight})
$: useIcon = !!icon $: useIcon = !!icon
</script> </script>
<div class="flatbutton" class:selected on:click={() => onClick(value || text)}> <div class="flatbutton" {style} class:selected on:click={() => onClick(value || text)}>
{#if useIcon} {#if useIcon}
<i class={icon} /> <i class={icon} />
{:else} {:else}
<span>{text}</span> <span>{@html text}</span>
{/if} {/if}
</div> </div>
<style> <style>
.flatbutton { .flatbutton {
cursor: pointer; cursor: pointer;
@ -28,6 +33,7 @@
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
transition: all 0.3s; transition: all 0.3s;
margin-left: 5px;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
@ -35,4 +41,8 @@
background: var(--ink-light); background: var(--ink-light);
color: #ffffff; color: #ffffff;
} }
i{
font-size: 20px;
}
</style> </style>

View File

@ -27,13 +27,18 @@
} }
onChange(val) onChange(val)
} }
const checkSelected = val =>
isMultiSelect ? value.includes(val) : value === val
</script> </script>
<div class="flatbutton-group"> <div class="flatbutton-group">
{#each buttonProps as props} {#each buttonProps as props}
<div class="button-container"> <div class="button-container">
<FlatButton <FlatButton
selected={value.includes(props.value)} selected={isMultiSelect ? value.includes(props.value) : value === props.value}
onClick={onButtonClicked} onClick={onButtonClicked}
{...props} /> {...props} />
</div> </div>

View File

@ -1,36 +1,223 @@
<script> <script>
import { onMount } from "svelte" import { onMount, beforeUpdate } from "svelte"
export let value = "" import {buildStyle} from "../../helpers.js"
export let onChange = value => {}
export let options = [] export let options = []
export let initialValue = "" export let value = ""
export let styleBindingProperty = "" export let styleBindingProperty
export let onChange = value => {}
let open = null
let rotate = ""
let select
let selectMenu
let icon
let selectYPosition = null
let availableSpace = 0
let positionSide = "top"
let maxHeight = null
let menuHeight
const handleStyleBind = value => const handleStyleBind = value =>
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {} !!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
$: isOptionsObject = options.every(o => typeof o === "object")
onMount(() => { onMount(() => {
if (!value && !!initialValue) { if (select) {
value = initialValue select.addEventListener("keydown", addSelectKeyEvents)
}
return () => {
select.removeEventListener("keydown", addSelectKeyEvents)
} }
}) })
function checkPosition() {
const { bottom, top: spaceAbove } = select.getBoundingClientRect()
const spaceBelow = window.innerHeight - bottom
if (spaceAbove > spaceBelow) {
positionSide = "bottom"
maxHeight = `${spaceAbove.toFixed(0) - 20}px`
} else {
positionSide = "top"
maxHeight = `${spaceBelow.toFixed(0) - 20}px`
}
}
function addSelectKeyEvents(e) {
if (e.key === "Enter") {
if (!open) {
toggleSelect(true)
}
} else if (e.key === "Escape") {
if (open) {
toggleSelect(false)
}
}
}
function toggleSelect(isOpen) {
checkPosition()
if (isOpen) {
icon.style.transform = "rotate(180deg)"
} else {
icon.style.transform = "rotate(0deg)"
}
open = isOpen
}
function handleClick(val) {
value = val
onChange(value)
}
$: menuStyle = buildStyle({
"max-height": maxHeight,
"transform-origin": `center ${positionSide}`,
[positionSide]: "32px",
})
$: isOptionsObject = options.every(o => typeof o === "object")
$: selectedOption = isOptionsObject
? options.find(o => o.value === value)
: {}
$: displayLabel =
selectedOption && selectedOption.label ? selectedOption.label : value || ""
</script> </script>
<select <div
class="uk-select uk-form-small" tabindex="0"
{value} bind:this={select}
on:change={ev => onChange(ev.target.value)}> class="bb-select-container"
{#if isOptionsObject} on:click={() => toggleSelect(!open)}>
{#each options as { value, label }} <div class="bb-select-anchor selected">
<option {...handleStyleBind(value || label)} value={value || label}> <span>{displayLabel}</span>
{label} <i bind:this={icon} class="ri-arrow-down-s-fill" />
</option> </div>
{/each} <div
{:else} bind:this={selectMenu}
{#each options as value} style={menuStyle}
<option {...handleStyleBind(value)} {value}>{value}</option> class="bb-select-menu"
{/each} class:open>
{/if} <ul>
</select> {#if isOptionsObject}
{#each options as { value: v, label }}
<li
{...handleStyleBind(v)}
on:click|self={handleClick(v)}
class:selected={value === v}>
{label}
</li>
{/each}
{:else}
{#each options as v}
<li
{...handleStyleBind(v)}
on:click|self={handleClick(v)}
class:selected={value === v}>
{v}
</li>
{/each}
{/if}
</ul>
</div>
</div>
{#if open}
<div on:click|self={() => toggleSelect(false)} class="overlay" />
{/if}
<style>
.overlay {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 1;
}
.bb-select-container {
position: relative;
outline: none;
width: 160px;
height: 32px;
cursor: pointer;
font-size: 12px;
}
.bb-select-anchor {
cursor: pointer;
display: flex;
padding: 5px 10px;
background-color: #f2f2f2;
border-radius: 2px;
border: 1px solid var(--grey-dark);
align-items: center;
}
.bb-select-anchor > span {
color: #565a66;
font-weight: 500;
width: 140px;
overflow-x: hidden;
}
.bb-select-anchor > i {
transition: transform 0.13s ease;
transform-origin: center;
width: 20px;
height: 20px;
text-align: center;
}
.selected {
color: #565a66;
font-weight: 500;
}
.bb-select-menu {
position: absolute;
display: flex;
box-sizing: border-box;
flex-direction: column;
opacity: 0;
width: 160px;
z-index: 2;
color: #808192;
font-weight: 500;
height: fit-content !important;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
border-right: 1px solid var(--grey-dark);
border-left: 1px solid var(--grey-dark);
border-bottom: 1px solid var(--grey-dark);
background-color: #f2f2f2;
transform: scale(0);
transition: opacity 0.13s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1);
overflow-y: auto;
}
.open {
transform: scale(1);
opacity: 1;
}
ul {
list-style-type: none;
margin: 0;
padding: 5px 0px;
}
li {
height: auto;
padding: 5px 0px;
cursor: pointer;
padding-left: 10px
}
li:hover {
background-color:#e6e6e6
}
</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 = ""
const handleStyleBind = value =>
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
$: isOptionsObject = options.every(o => typeof o === "object")
onMount(() => {
if (!value && !!initialValue) {
value = initialValue
}
})
</script>
<select {value} on:change={ev => onChange(ev.target.value)}>
{#if isOptionsObject}
{#each options as { value, label }}
<option {...handleStyleBind(value || label)} value={value || label}>
{label}
</option>
{/each}
{:else}
{#each options as value}
<option {...handleStyleBind(value)} {value}>{value}</option>
{/each}
{/if}
</select>

View File

@ -50,6 +50,9 @@
.label { .label {
flex: 0 0 50px; flex: 0 0 50px;
display: flex;
align-items: center;
padding: 0px 5px;
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
text-align: left; text-align: left;
@ -60,6 +63,7 @@
.control { .control {
flex: 1; flex: 1;
display: flex;
padding-left: 2px; padding-left: 2px;
max-width: 164px; max-width: 164px;
} }

View File

@ -71,12 +71,16 @@
} }
.property-panel { .property-panel {
height: 0px; /* height: 0px;
overflow: hidden; overflow: hidden; */
display: none;
} }
.show { .show {
overflow: auto; /* overflow: auto;
height: auto; height: auto; */
display: flex;
flex-direction: column;
flex: 1;
} }
</style> </style>

View File

@ -123,8 +123,7 @@
.components-pane { .components-pane {
grid-column: 3; grid-column: 3;
background-color: var(--white); background-color: var(--white);
height: 100vh; height: calc(100vh - 49px);
overflow-y: scroll;
} }
.components-nav-page { .components-nav-page {

View File

@ -1,6 +1,7 @@
import Input from "../common/Input.svelte" import Input from "../common/Input.svelte"
import OptionSelect from "./OptionSelect.svelte" import OptionSelect from "./OptionSelect.svelte"
import InputGroup from "../common/Inputs/InputGroup.svelte" import InputGroup from "../common/Inputs/InputGroup.svelte"
import FlatButtonGroup from "./FlatButtonGroup.svelte"
// import Colorpicker from "../common/Colorpicker.svelte" // import Colorpicker from "../common/Colorpicker.svelte"
/* /*
TODO: Allow for default values for all properties TODO: Allow for default values for all properties
@ -11,9 +12,8 @@ export const layout = [
label: "Display", label: "Display",
key: "display", key: "display",
control: OptionSelect, control: OptionSelect,
initialValue: "Select Option", initialValue: "Flex",
options: [ options: [
{ label: "Select Option", value: "" },
{ label: "Flex", value: "flex" }, { label: "Flex", value: "flex" },
{ label: "Inline Flex", value: "inline-flex" }, { label: "Inline Flex", value: "inline-flex" },
], ],
@ -21,23 +21,24 @@ export const layout = [
{ {
label: "Direction", label: "Direction",
key: "flex-direction", key: "flex-direction",
control: OptionSelect, control: FlatButtonGroup,
initialValue: "Select Option", buttonProps: [
options: [ { icon: "ri-arrow-right-line", padding: "0px 5px", value: "row" },
{ label: "Select Option", value: "" }, { icon: "ri-arrow-left-line", padding: "0px 5px", value: "rowReverse" },
{ label: "Row", value: "row" }, { icon: "ri-arrow-down-line", padding: "0px 5px", value: "column" },
{ label: "Row Reverse", value: "rowReverse" }, {
{ label: "Column", value: "column" }, icon: "ri-arrow-up-line",
{ label: "Column Reverse", value: "columnReverse" }, padding: "0px 5px",
value: "columnReverse",
},
], ],
}, },
{ {
label: "Justify", label: "Justify",
key: "justify-content", key: "justify-content",
control: OptionSelect, control: OptionSelect,
initialValue: "Select Option", initialValue: "Flex Start",
options: [ options: [
{ label: "Select Option", value: "" },
{ label: "Flex Start", value: "flex-start" }, { label: "Flex Start", value: "flex-start" },
{ label: "Flex End", value: "flex-end" }, { label: "Flex End", value: "flex-end" },
{ label: "Center", value: "center" }, { label: "Center", value: "center" },
@ -50,9 +51,8 @@ export const layout = [
label: "Align", label: "Align",
key: "align-items", key: "align-items",
control: OptionSelect, control: OptionSelect,
initialValue: "Select Option", initialValue: "Flex Start",
options: [ options: [
{ label: "Select Option", value: "" },
{ label: "Flex Start", value: "flex-start" }, { label: "Flex Start", value: "flex-start" },
{ label: "Flex End", value: "flex-end" }, { label: "Flex End", value: "flex-end" },
{ label: "Center", value: "center" }, { label: "Center", value: "center" },
@ -64,12 +64,9 @@ export const layout = [
label: "Wrap", label: "Wrap",
key: "flex-wrap", key: "flex-wrap",
control: OptionSelect, control: OptionSelect,
initialValue: "Select Option",
options: [ options: [
{ label: "Select Option", value: "" }, { label: "wrap", value: "wrap" },
{ label: "No Wrap", value: "nowrap" }, { label: "no wrap", value: "noWrap" },
{ label: "Wrap", value: "wrap" },
{ label: "Wrap Reverse", value: "wrap-reverse" },
], ],
}, },
] ]
@ -82,22 +79,73 @@ const spacingMeta = [
] ]
export const spacing = [ export const spacing = [
{ label: "Margin", key: "margin", control: InputGroup, meta: spacingMeta }, {
label: "Margin",
key: "margin",
control: InputGroup,
meta: spacingMeta,
suffix: "px",
defaultValue: ["0", "0", "0", "0"],
},
{ {
label: "Padding", label: "Padding",
key: "padding", key: "padding",
control: InputGroup, control: InputGroup,
meta: spacingMeta, meta: spacingMeta,
suffix: "px",
defaultValue: ["0", "0", "0", "0"],
}, },
] ]
export const size = [ export const size = [
{ label: "Width", key: "width", control: Input }, {
{ label: "Height", key: "height", control: Input }, label: "Width",
{ label: "Min W", key: "min-width", control: Input }, key: "width",
{ label: "Min H", key: "min-height", control: Input }, control: Input,
{ label: "Max W", key: "max-width", control: Input }, placeholder: "px",
{ label: "Max H", key: "max-height", control: Input }, width: "48px",
textAlign: "center",
},
{
label: "Height",
key: "height",
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
},
{
label: "Min W",
key: "min-width",
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
},
{
label: "Min H",
key: "min-height",
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
},
{
label: "Max W",
key: "max-width",
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
},
{
label: "Max H",
key: "max-height",
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
},
] ]
export const position = [ export const position = [
@ -118,26 +166,41 @@ export const position = [
label: "Top", label: "Top",
key: "top", key: "top",
control: Input, control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
}, },
{ {
label: "Right", label: "Right",
key: "right", key: "right",
control: Input, control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
}, },
{ {
label: "Bottom", label: "Bottom",
key: "bottom", key: "bottom",
control: Input, control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
}, },
{ {
label: "Left", label: "Left",
key: "left", key: "left",
control: Input, control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
}, },
{ {
label: "Z-index", label: "Z-index",
key: "z-index", key: "z-index",
control: Input, control: Input,
placeholder: "num",
width: "48px",
textAlign: "center",
}, },
] ]
@ -171,47 +234,59 @@ export const typography = [
label: "Weight", label: "Weight",
key: "font-weight", key: "font-weight",
control: OptionSelect, control: OptionSelect,
options: [ options: ["normal", "bold", "bolder", "lighter"],
{ label: "100", value: "100" }, },
{ label: "200", value: "200" }, {
{ label: "300", value: "300" }, label: "size",
{ label: "400", value: "400" }, key: "font-size",
{ label: "500", value: "500" }, defaultValue: "",
{ label: "600", value: "600" }, control: Input,
{ label: "700", value: "700" }, placeholder: "px",
{ label: "800", value: "800" }, width: "48px",
{ label: "900", value: "900" }, textAlign: "center",
], },
{
label: "Line H",
key: "line-height",
control: Input,
placeholder: "lh",
width: "48px",
textAlign: "center",
}, },
{ label: "size", key: "font-size", defaultValue: "", control: Input },
{ label: "Line H", key: "line-height", control: Input },
{ {
label: "Color", label: "Color",
key: "color", key: "color",
control: Input, control: Input,
placeholder: "hex",
}, },
{ {
label: "align", label: "align",
key: "text-align", key: "text-align",
control: OptionSelect, control: FlatButtonGroup,
options: ["initial", "left", "right", "center", "justify"], buttonProps: [
}, //custom { icon: "ri-align-left", padding: "0px 5px", value: "left" },
{ { icon: "ri-align-center", padding: "0px 5px", value: "center" },
label: "Decoration", { icon: "ri-align-right", padding: "0px 5px", value: "right" },
key: "text-decoration-line", { icon: "ri-align-justify", padding: "0px 5px", value: "justify" },
control: OptionSelect,
defaultValue: "None",
options: [
{ label: "None", value: "none" },
{ label: "Underline", value: "underline" },
{ label: "Overline", value: "overline" },
{ label: "Line-through", value: "line-through" },
{ label: "Under Over", value: "underline overline" },
], ],
}, },
{
{ label: "transform", key: "text-transform", control: Input }, //custom label: "transform",
{ label: "style", key: "font-style", control: Input }, //custom key: "text-transform",
control: FlatButtonGroup,
buttonProps: [
{ text: "BB", padding: "0px 5px", fontWeight: 500, value: "uppercase" },
{ text: "Bb", padding: "0px 5px", fontWeight: 500, value: "capitalize" },
{ text: "bb", padding: "0px 5px", fontWeight: 500, value: "lowercase" },
{
text: "&times;",
padding: "0px 5px",
fontWeight: 500,
value: "none",
},
],
},
{ label: "style", key: "font-style", control: Input },
] ]
export const background = [ export const background = [
@ -220,12 +295,31 @@ export const background = [
key: "background", key: "background",
control: Input, control: Input,
}, },
{ label: "Image", key: "image", control: Input }, //custom {
label: "Image",
key: "background-image",
control: Input,
placeholder: "src",
},
] ]
export const border = [ export const border = [
{ label: "Radius", key: "border-radius", control: Input }, {
{ label: "Width", key: "border-width", control: Input }, //custom label: "Radius",
key: "border-radius",
control: Input,
width: "48px",
placeholder: "px",
textAlign: "center",
},
{
label: "Width",
key: "border-width",
control: Input,
width: "48px",
placeholder: "px",
textAlign: "center",
}, //custom
{ {
label: "Color", label: "Color",
key: "border-color", key: "border-color",
@ -251,30 +345,65 @@ export const border = [
] ]
export const effects = [ export const effects = [
{ label: "Opacity", key: "opacity", control: Input }, {
label: "Opacity",
key: "opacity",
control: Input,
width: "48px",
textAlign: "center",
placeholder: "%",
},
{ {
label: "Rotate", label: "Rotate",
key: "transform", key: "transform",
control: OptionSelect, control: Input,
options: [ width: "48px",
{ label: "None", value: "rotate(0deg)" }, textAlign: "center",
{ label: "45 degrees", value: "rotate(45deg)" }, placeholder: "deg",
{ label: "90 degrees", value: "rotate(90deg)" },
{ label: "135 degrees", value: "rotate(135deg)" },
{ label: "180 degrees", value: "rotate(180deg)" },
{ label: "225 degrees", value: "rotate(225deg)" },
{ label: "270 degrees", value: "rotate(270deg)" },
{ label: "315 degrees", value: "rotate(315deg)" },
{ label: "360 degrees", value: "rotate(360deg)" },
],
}, //needs special control }, //needs special control
{ label: "Shadow", key: "box-shadow", control: Input }, {
label: "Shadow",
key: "box-shadow",
control: InputGroup,
meta: [{ placeholder: "X" }, { placeholder: "Y" }, { placeholder: "B" }],
},
] ]
export const transitions = [ export const transitions = [
{ label: "Property", key: "transition-property", control: Input }, {
{ label: "Duration", key: "transition-timing-function", control: Input }, label: "Property",
{ label: "Ease", key: "transition-ease", control: Input }, key: "transition-property",
control: OptionSelect,
options: [
"None",
"All",
"Background Color",
"Color",
"Font Size",
"Font Weight",
"Height",
"Margin",
"Opacity",
"Padding",
"Rotate",
"Shadow",
"Width",
],
},
{
label: "Duration",
key: "transition-timing-function",
control: Input,
width: "48px",
textAlign: "center",
placeholder: "sec",
},
{
label: "Ease",
key: "transition-ease",
control: OptionSelect,
options: ["linear", "ease", "ease-in", "ease-out", "ease-in-out"],
},
] ]
export const all = { export const all = {

View File

@ -0,0 +1,14 @@
export const buildStyle = styles => {
let str = ""
for (let s in styles) {
if (styles[s]) {
let key = convertCamel(s)
str += `${key}: ${styles[s]}; `
}
}
return str
}
export const convertCamel = str => {
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)
}

View File

@ -84,7 +84,7 @@
.ui-nav { .ui-nav {
grid-column: 1; grid-column: 1;
background-color: var(--white); background-color: var(--white);
height: calc(100vh - 49px); height: calc(100vh - 69px);
padding: 0; padding: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -101,6 +101,47 @@
.components-pane { .components-pane {
grid-column: 3; grid-column: 3;
background-color: var(--white); background-color: var(--white);
min-height: 0px;
height: calc(100vh - 69px);
overflow-y: hidden;
}
.components-nav-page {
font-size: 13px;
color: var(--ink);
padding-left: 20px;
margin-top: 20px;
font-weight: 600;
opacity: 0.4;
letter-spacing: 1px;
}
.components-nav-header {
font-size: 13px;
color: var(--ink);
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;
min-height: 0; min-height: 0;
} }

View File

@ -1,14 +1,10 @@
import { import {
generate_css, generate_css,
generate_screen_css, generate_screen_css,
generate_array_styles
} from "../src/builderStore/generate_css.js" } from "../src/builderStore/generate_css.js"
describe("generate_css", () => { describe("generate_css", () => {
test("Check how partially empty arrays are handled", () => {
expect(["", "5", "", ""].map(generate_array_styles)).toEqual(["0px", "5px", "0px", "0px"])
})
test("Check how array styles are output", () => { test("Check how array styles are output", () => {
expect(generate_css({ margin: ["0", "10", "0", "15"] })).toBe("margin: 0px 10px 0px 15px;") expect(generate_css({ margin: ["0", "10", "0", "15"] })).toBe("margin: 0px 10px 0px 15px;")