Completed CSS Selector Styling
This commit is contained in:
parent
0a745edfe4
commit
deab1adc31
|
@ -1,119 +1,21 @@
|
|||
import { pipe } from "components/common/core"
|
||||
import { filter, map, reduce, toPairs } from "lodash/fp"
|
||||
|
||||
const self = n => n
|
||||
const join_with = delimiter => a => a.join(delimiter)
|
||||
const empty_string_to_unset = s => (s.length ? s : "0")
|
||||
const add_suffix_if_number = suffix => s => {
|
||||
try {
|
||||
if (isNaN(s) || isNaN(parseFloat(s))) return s
|
||||
} catch (_) {
|
||||
return s
|
||||
export const generate_screen_css = component_arr => {
|
||||
let styles = ""
|
||||
for (const { _styles, _id, _children, _component } of component_arr) {
|
||||
let [componentName] = _component.match(/[a-z]*$/)
|
||||
Object.keys(_styles).forEach(selector => {
|
||||
const cssString = generate_css(_styles[selector])
|
||||
if (cssString) {
|
||||
styles += apply_class(_id, componentName, cssString, selector)
|
||||
}
|
||||
})
|
||||
if (_children && _children.length) {
|
||||
styles += generate_screen_css(_children) + "\n"
|
||||
}
|
||||
}
|
||||
return s + suffix
|
||||
return styles.trim()
|
||||
}
|
||||
|
||||
export const make_margin = values =>
|
||||
pipe(values, [
|
||||
map(empty_string_to_unset),
|
||||
map(add_suffix_if_number("px")),
|
||||
join_with(" "),
|
||||
])
|
||||
|
||||
const css_map = {
|
||||
templaterows: {
|
||||
name: "grid-template-rows",
|
||||
generate: self,
|
||||
},
|
||||
templatecolumns: {
|
||||
name: "grid-template-columns",
|
||||
generate: self,
|
||||
},
|
||||
align: {
|
||||
name: "align-items",
|
||||
generate: self,
|
||||
},
|
||||
justify: {
|
||||
name: "justify-content",
|
||||
generate: self,
|
||||
},
|
||||
direction: {
|
||||
name: "flex-direction",
|
||||
generate: self,
|
||||
},
|
||||
gridarea: {
|
||||
name: "grid-area",
|
||||
generate: make_margin,
|
||||
},
|
||||
gap: {
|
||||
name: "grid-gap",
|
||||
generate: n => `${n}px`,
|
||||
},
|
||||
columnstart: {
|
||||
name: "grid-column-start",
|
||||
generate: self,
|
||||
},
|
||||
columnend: {
|
||||
name: "grid-column-end",
|
||||
generate: self,
|
||||
},
|
||||
rowstart: {
|
||||
name: "grid-row-start",
|
||||
generate: self,
|
||||
},
|
||||
rowend: {
|
||||
name: "grid-row-end",
|
||||
generate: self,
|
||||
},
|
||||
padding: {
|
||||
name: "padding",
|
||||
generate: make_margin,
|
||||
},
|
||||
margin: {
|
||||
name: "margin",
|
||||
generate: make_margin,
|
||||
},
|
||||
zindex: {
|
||||
name: "z-index",
|
||||
generate: self,
|
||||
},
|
||||
height: {
|
||||
name: "height",
|
||||
generate: self,
|
||||
},
|
||||
width: {
|
||||
name: "width",
|
||||
generate: self,
|
||||
},
|
||||
}
|
||||
|
||||
//Only used here
|
||||
export const generate_rule = ([name, values]) =>
|
||||
`${css_map[name].name}: ${css_map[name].generate(values)};`
|
||||
|
||||
const handle_grid = (acc, [name, value]) => {
|
||||
let tmp = []
|
||||
|
||||
if (name === "row" || name === "column") {
|
||||
if (value[0]) tmp.push([`${name}start`, value[0]])
|
||||
if (value[1]) tmp.push([`${name}end`, value[1]])
|
||||
return acc.concat(tmp)
|
||||
}
|
||||
|
||||
return acc.concat([[name, value]])
|
||||
}
|
||||
|
||||
const object_to_css_string = [
|
||||
toPairs,
|
||||
reduce(handle_grid, []),
|
||||
filter(v => (Array.isArray(v[1]) ? v[1].some(s => s.length) : v[1].length)),
|
||||
map(generate_rule),
|
||||
join_with("\n"),
|
||||
]
|
||||
|
||||
//USED BY generate_screen_css
|
||||
export const generate_css = style => {
|
||||
// let cssString = pipe(style, object_to_css_string)
|
||||
let cssString = Object.entries(style).reduce((str, [key, value]) => {
|
||||
//TODO Handle arrays and objects here also
|
||||
if (typeof value === "string") {
|
||||
|
@ -130,23 +32,12 @@ export const generate_css = style => {
|
|||
return (cssString || "").trim()
|
||||
}
|
||||
|
||||
const apply_class = (id, name, styles) => `.${name}-${id} {\n${styles}\n}`
|
||||
|
||||
//USED IN MULTIPLE PLACES IN THE BUILDER STORE
|
||||
export const generate_screen_css = component_array => {
|
||||
let styles = ""
|
||||
let emptyStyles = { normal: {}, hover: {}, active: {}, selected: {} }
|
||||
for (let i = 0; i < component_array.length; i += 1) {
|
||||
const { _styles, _id, _children, _component } = component_array[i]
|
||||
// let [componentName] = _component.match(/[a-z]*$/)
|
||||
debugger
|
||||
const cssString = generate_css(_styles || emptyStyles) || ""
|
||||
if (cssString) {
|
||||
styles += apply_class(_id, "element", cssString)
|
||||
}
|
||||
if (_children && _children.length) {
|
||||
styles += generate_screen_css(_children) + "\n"
|
||||
}
|
||||
const apply_class = (id, name = "element", styles, selector) => {
|
||||
if (selector === "normal") {
|
||||
return `.${name}-${id} {\n${styles}\n}`
|
||||
} else {
|
||||
let sel = selector === "selected" ? "::selection" : `:${selector}`
|
||||
return `.${name}-${id}${sel} {\n${styles}\n}`
|
||||
}
|
||||
return styles.trim()
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,6 @@ const _saveScreen = async (store, s, screen) => {
|
|||
}
|
||||
|
||||
const _saveScreenApi = (screen, s) => {
|
||||
|
||||
api
|
||||
.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen)
|
||||
.then(() => _savePage(s))
|
||||
|
@ -427,8 +426,7 @@ const setComponentStyle = store => (type, name, value) => {
|
|||
if (!state.currentComponentInfo._styles) {
|
||||
state.currentComponentInfo._styles = {}
|
||||
}
|
||||
// state.currentComponentInfo._styles[type][name] = value
|
||||
state.currentComponentInfo._styles[name] = value
|
||||
state.currentComponentInfo._styles[type][name] = value
|
||||
|
||||
state.currentPreviewItem._css = generate_screen_css([
|
||||
state.currentPreviewItem.props,
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<input
|
||||
{type}
|
||||
placeholder={placeholder || ''}
|
||||
value={value[i] === 0 ? '' : value[i]}
|
||||
value={!value || value[i] === 0 ? '' : value[i]}
|
||||
on:change={e => handleChange(e.target.value || 0, i)} />
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
return props
|
||||
}
|
||||
|
||||
const getComponentTypeName = component => {
|
||||
let [componentName] = component._component.match(/[a-z]*$/)
|
||||
return componentName || "element"
|
||||
}
|
||||
|
||||
$: iframe &&
|
||||
console.log(
|
||||
iframe.contentDocument.head.insertAdjacentHTML(
|
||||
|
@ -93,6 +98,8 @@
|
|||
appRootPath: "",
|
||||
}
|
||||
|
||||
$: selectedComponentType = getComponentTypeName($store.currentComponentInfo)
|
||||
|
||||
$: selectedComponentId = $store.currentComponentInfo
|
||||
? $store.currentComponentInfo._id
|
||||
: ""
|
||||
|
@ -107,6 +114,7 @@
|
|||
srcdoc={iframeTemplate({
|
||||
styles,
|
||||
stylesheetLinks,
|
||||
selectedComponentType,
|
||||
selectedComponentId,
|
||||
frontendDefinition: JSON.stringify(frontendDefinition),
|
||||
currentPageFunctions: $store.currentPageFunctions,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export default ({
|
||||
styles,
|
||||
stylesheetLinks,
|
||||
selectedComponentType,
|
||||
selectedComponentId,
|
||||
frontendDefinition,
|
||||
currentPageFunctions,
|
||||
|
@ -11,7 +12,7 @@ export default ({
|
|||
<style>
|
||||
${styles || ""}
|
||||
|
||||
.element-${selectedComponentId} {
|
||||
.${selectedComponentType}-${selectedComponentId} {
|
||||
border: 2px solid #0055ff;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
const safeValue = () => {
|
||||
return value === undefined && props.defaultValue !== undefined
|
||||
? props.defaultValue
|
||||
: value
|
||||
}
|
||||
|
||||
//Incase the component has a different value key name
|
||||
const handlevalueKey = value =>
|
||||
props.valueKey ? { [props.valueKey]: value } : { value }
|
||||
props.valueKey ? { [props.valueKey]: safeValue() } : { value: safeValue() }
|
||||
</script>
|
||||
|
||||
<div class="property-control">
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
const capitalize = name => name[0].toUpperCase() + name.slice(1)
|
||||
|
||||
$: icon = show ? "ri-arrow-down-s-fill" : "ri-arrow-right-s-fill"
|
||||
$: style = componentInstance["_styles"][styleCategory] || {}
|
||||
</script>
|
||||
|
||||
<div class="property-group-container">
|
||||
|
@ -29,8 +30,8 @@
|
|||
label={props.label}
|
||||
control={props.control}
|
||||
key={props.key}
|
||||
value={componentInstance['_styles'][props.key]}
|
||||
onChange={(key, value) => onStyleChanged(name, key, value)}
|
||||
value={style[props.key]}
|
||||
onChange={(key, value) => onStyleChanged(styleCategory, key, value)}
|
||||
props={{ ...excludeProps(props, ['control', 'label']) }} />
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Input from "../common/Input.svelte"
|
||||
import OptionSelect from "./OptionSelect.svelte"
|
||||
import InputGroup from "../common/Inputs/InputGroup.svelte"
|
||||
import Colorpicker from "../common/Colorpicker.svelte"
|
||||
// import Colorpicker from "../common/Colorpicker.svelte"
|
||||
/*
|
||||
TODO: Allow for default values for all properties
|
||||
*/
|
||||
|
@ -74,15 +74,16 @@ export const typography = [
|
|||
label: "Font",
|
||||
key: "font-family",
|
||||
control: OptionSelect,
|
||||
defaultValue: "initial",
|
||||
options: [
|
||||
{ label: "initial" },
|
||||
{ label: "Times New Roman" },
|
||||
{ label: "Georgia" },
|
||||
{ label: "Arial" },
|
||||
{ label: "Arial Black" },
|
||||
{ label: "Comic Sans MS" },
|
||||
{ label: "Impact" },
|
||||
{ label: "Lucida Sans Unicode" },
|
||||
"initial",
|
||||
"Times New Roman",
|
||||
"Georgia",
|
||||
"Arial",
|
||||
"Arial Black",
|
||||
"Comic Sans MS",
|
||||
"Impact",
|
||||
"Lucida Sans Unicode",
|
||||
],
|
||||
styleBindingProperty: "font-family",
|
||||
},
|
||||
|
@ -97,12 +98,13 @@ export const typography = [
|
|||
{ label: "lighter" },
|
||||
],
|
||||
},
|
||||
{ label: "size", key: "font-size", control: Input },
|
||||
{ label: "size", key: "font-size", defaultValue: "", control: Input },
|
||||
{ label: "Line H", key: "line-height", control: Input },
|
||||
{
|
||||
label: "Color",
|
||||
key: "color",
|
||||
control: Colorpicker,
|
||||
control: OptionSelect,
|
||||
options: ["black", "white", "red", "blue", "green"],
|
||||
},
|
||||
{
|
||||
label: "align",
|
||||
|
@ -118,7 +120,8 @@ export const background = [
|
|||
{
|
||||
label: "Background",
|
||||
key: "background",
|
||||
control: Colorpicker,
|
||||
control: OptionSelect,
|
||||
options: ["black", "white", "red", "blue", "green"],
|
||||
},
|
||||
{ label: "Image", key: "image", control: Input }, //custom
|
||||
]
|
||||
|
@ -126,7 +129,10 @@ export const background = [
|
|||
export const border = [
|
||||
{ label: "Radius", key: "border-radius", control: Input },
|
||||
{ label: "Width", key: "border-width", control: Input }, //custom
|
||||
{ label: "Color", key: "border-color", control: Colorpicker },
|
||||
{
|
||||
label: "Color", key: "border-color", control: OptionSelect,
|
||||
options: ["black", "white", "red", "blue", "green"]
|
||||
},
|
||||
{ label: "Style", key: "border-style", control: Input },
|
||||
]
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<link rel='stylesheet' href='/_builder/bundle.css'>
|
||||
<link rel='stylesheet' href='/_builder/fonts.css'>
|
||||
<link rel='stylesheet' href="/_builder/uikit.min.css">
|
||||
<link rel='stylesheet' href="/_builder/nano.min.css">
|
||||
</head>
|
||||
|
||||
<body id="app">
|
||||
|
|
|
@ -35,8 +35,9 @@ export const prepareRenderComponent = ({
|
|||
thisNode.rootElement =
|
||||
htmlElement.children[htmlElement.children.length - 1]
|
||||
|
||||
let [componentName] = props._component.match(/[a-z]*$/)
|
||||
if (props._id && thisNode.rootElement) {
|
||||
thisNode.rootElement.classList.add(`element-${props._id}`)
|
||||
thisNode.rootElement.classList.add(`${componentName}-${props._id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue