Properties panel structure complete
This commit is contained in:
parent
391237403b
commit
6d70cfd1c1
|
@ -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 {
|
||||
|
|
|
@ -49,8 +49,6 @@
|
|||
const onPropChanged = store.setComponentProp
|
||||
const onStyleChanged = store.setComponentStyle
|
||||
|
||||
//May be able to remove some of the nested components in PropsView, PropsControl and StateBindingControl tree
|
||||
|
||||
function walkProps(component, action) {
|
||||
action(component)
|
||||
if (component.children) {
|
||||
|
@ -98,45 +96,11 @@
|
|||
</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%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.title > div:nth-child(1) {
|
||||
|
@ -152,52 +116,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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,23 +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]
|
||||
|
||||
$: console.log("PDEF", panelDefinition)
|
||||
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>
|
||||
|
||||
{#each propertyGroupNames as groupName}
|
||||
<PropertyGroup
|
||||
name={groupName}
|
||||
properties={getProperties(groupName)}
|
||||
{onPropChanged}
|
||||
{componentDefinition}
|
||||
{componentInstance} />
|
||||
{/each}
|
||||
<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,22 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
export let value = ""
|
||||
export let onChange = value => {}
|
||||
export let options = []
|
||||
export let initialValue = ""
|
||||
|
||||
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 }}
|
||||
<option value={value || label}>{label}</option>
|
||||
{/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>
|
|
@ -1,28 +1,27 @@
|
|||
<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 = () => {}
|
||||
|
||||
let show = true
|
||||
export let show = false
|
||||
|
||||
const propExistsOnComponentDef = prop => prop in componentDefinition.props
|
||||
const capitalize = name => name[0].toUpperCase() + name.slice(1)
|
||||
|
||||
function onChange(v) {
|
||||
!!v.target ? onPropChanged(v.target.value) : onPropChanged(v)
|
||||
function onChange(key, v) {
|
||||
!!v.target ? onPropChanged(key, v.target.value) : onPropChanged(key, v)
|
||||
}
|
||||
|
||||
$: propertyDefinition = Object.entries(properties)
|
||||
$: console.log("props group", properties)
|
||||
$: icon = show ? "ri-arrow-down-s-fill" : "ri-arrow-right-s-fill"
|
||||
</script>
|
||||
|
||||
<!-- () => (show = !show) -->
|
||||
<div class="property-group-container" on:click={() => {}}>
|
||||
<div class="property-group-name">
|
||||
<div class="property-group-container">
|
||||
<div class="property-group-name" on:click={() => (show = !show)}>
|
||||
<div class="icon">
|
||||
<i class={icon} />
|
||||
</div>
|
||||
|
@ -31,17 +30,14 @@
|
|||
<div class="property-panel" class:show>
|
||||
|
||||
{#each propertyDefinition as [key, definition]}
|
||||
<div class="property-control">
|
||||
{#if propExistsOnComponentDef(key)}
|
||||
<span>{definition.label || capitalize(key)}</span>
|
||||
<svelte:component
|
||||
this={definition.control}
|
||||
value={componentInstance[key]}
|
||||
on:change={onChange}
|
||||
{onChange}
|
||||
{...excludeProps(definition, ['control'])} />
|
||||
{/if}
|
||||
</div>
|
||||
<!-- {#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>
|
||||
|
@ -63,14 +59,19 @@
|
|||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex: 0 0 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.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 {
|
||||
|
@ -78,11 +79,6 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.property-control {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.show {
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<script>
|
||||
export let value = ""
|
||||
export let onChange = value => {}
|
||||
export let options = []
|
||||
</script>
|
||||
|
||||
<select
|
||||
class="uk-select uk-form-small"
|
||||
{value}
|
||||
on:change={ev => onChange(ev.target.value)}>
|
||||
{#each options || [] as option}
|
||||
<option value={option}>{option}</option>
|
||||
{/each}
|
||||
</select>
|
|
@ -114,7 +114,7 @@
|
|||
|
||||
.root {
|
||||
display: grid;
|
||||
grid-template-columns: 275px 1fr 275px;
|
||||
grid-template-columns: 275px 1fr 300px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #fafafa;
|
||||
|
@ -151,7 +151,7 @@
|
|||
.components-pane {
|
||||
grid-column: 3;
|
||||
background-color: var(--white);
|
||||
min-height: 0px;
|
||||
height: 100vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,75 +1,102 @@
|
|||
import ColorPicker from "../common/Colorpicker.svelte"
|
||||
import Input from "../common/Input.svelte"
|
||||
import TempSelect from "./TempSelect.svelte"
|
||||
import OptionSelect from "./OptionSelect.svelte"
|
||||
/*
|
||||
TODO: all strings types are really inputs and could be typed as such
|
||||
TODO: Options types need option items
|
||||
TODO: Allow for default values for all properties
|
||||
*/
|
||||
|
||||
export const general = {
|
||||
text: { control: Input }
|
||||
text: { control: Input },
|
||||
}
|
||||
|
||||
export const layout = {
|
||||
flexDirection: { label: "Direction", control: "string" },
|
||||
justifyContent: { label: "Justify", control: "string" },
|
||||
alignItems: { label: "Align", control: "string" },
|
||||
flexWrap: { label: "Wrap", control: "options" },
|
||||
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: "string" },
|
||||
margin: { control: "string" },
|
||||
padding: { control: Input },
|
||||
margin: { control: Input },
|
||||
}
|
||||
|
||||
export const size = {
|
||||
width: { control: "string" },
|
||||
height: { control: "string" },
|
||||
minWidth: { label: "Min W", control: "string" },
|
||||
minHeight: { label: "Min H", control: "string" },
|
||||
maxWidth: { label: "Max W", control: "string" },
|
||||
maxHeight: { label: "Max H", control: "string" },
|
||||
overflow: { control: "string" }, //custom
|
||||
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: Input }, //custom
|
||||
}
|
||||
|
||||
export const position = {
|
||||
position: { control: "options" },
|
||||
position: { control: Input },
|
||||
}
|
||||
|
||||
export const typography = {
|
||||
font: { control: "options" },
|
||||
weight: { control: "options" },
|
||||
size: { control: "string" },
|
||||
lineHeight: { label: "Line H", control: "string" },
|
||||
color: { control: "colour" },
|
||||
align: { control: "string" }, //custom
|
||||
transform: { control: "string" }, //custom
|
||||
style: { control: "string" }, //custom
|
||||
font: { control: Input },
|
||||
weight: { control: Input },
|
||||
size: { control: Input },
|
||||
lineHeight: { label: "Line H", control: Input },
|
||||
color: {
|
||||
control: OptionSelect,
|
||||
options: [{ label: "red" }, { label: "blue" }, { label: "green" }],
|
||||
},
|
||||
align: { control: Input }, //custom
|
||||
transform: { control: Input }, //custom
|
||||
style: { control: Input }, //custom
|
||||
}
|
||||
|
||||
export const background = {
|
||||
backgroundColor: { label: "Background Color", control: ColorPicker },
|
||||
backgroundColor: { label: "Background Color", control: Input },
|
||||
image: { control: Input }, //custom
|
||||
}
|
||||
|
||||
export const border = {
|
||||
radius: { control: "string" },
|
||||
width: { control: "string" }, //custom
|
||||
color: { control: "colour" },
|
||||
style: { control: "options" },
|
||||
radius: { control: Input },
|
||||
width: { control: Input }, //custom
|
||||
color: { control: Input },
|
||||
style: { control: Input },
|
||||
}
|
||||
|
||||
export const effects = {
|
||||
opacity: "string",
|
||||
rotate: "string",
|
||||
shadow: "string",
|
||||
opacity: { control: Input },
|
||||
rotate: { control: Input },
|
||||
shadow: { control: Input },
|
||||
}
|
||||
|
||||
export const transitions = {
|
||||
property: { control: "options" },
|
||||
duration: { control: "string" },
|
||||
ease: { control: "options" },
|
||||
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) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { general, layout, background } from "./propertyCategories.js"
|
||||
import { general, layout, typography, background, all } from "./propertyCategories.js"
|
||||
|
||||
export default {
|
||||
categories: [
|
||||
|
@ -13,7 +13,7 @@ export default {
|
|||
icon: 'ri-layout-row-fill',
|
||||
commonProps: {},
|
||||
children: [],
|
||||
properties: { background },
|
||||
properties: { ...all },
|
||||
},
|
||||
{
|
||||
name: 'Text',
|
||||
|
@ -29,7 +29,7 @@ export default {
|
|||
properties: {
|
||||
general,
|
||||
layout,
|
||||
background,
|
||||
typography,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue