diff --git a/packages/builder/assets/banner-image.png b/packages/builder/assets/banner-image.png new file mode 100644 index 0000000000..3531495668 Binary files /dev/null and b/packages/builder/assets/banner-image.png differ diff --git a/packages/builder/assets/bb-logo.svg b/packages/builder/assets/bb-logo.svg new file mode 100644 index 0000000000..7d115faefc --- /dev/null +++ b/packages/builder/assets/bb-logo.svg @@ -0,0 +1,31 @@ + + + diff --git a/packages/builder/package.json b/packages/builder/package.json index cb91f2ce42..086d22382a 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -82,4 +82,4 @@ "svelte": "^3.0.0" }, "gitHead": "115189f72a850bfb52b65ec61d932531bf327072" -} \ No newline at end of file +} diff --git a/packages/builder/src/builderStore/generate_css.js b/packages/builder/src/builderStore/generate_css.js index 4326e7cb0f..5826d4f824 100644 --- a/packages/builder/src/builderStore/generate_css.js +++ b/packages/builder/src/builderStore/generate_css.js @@ -1,142 +1,54 @@ -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 - } - return s + suffix -} - -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, - }, -} - -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"), -] - -export const generate_css = ({ layout, position }) => { - let _layout = pipe(layout, object_to_css_string) - if (_layout.length) { - _layout += `\ndisplay: ${_layout.includes("flex") ? "flex" : "grid"};` - } - - return { - layout: _layout, - position: pipe(position, object_to_css_string), - } -} - -const apply_class = (id, name, styles) => `.${name}-${id} {\n${styles}\n}` - -export const generate_screen_css = component_array => { +export const generate_screen_css = component_arr => { let styles = "" - let emptyStyles = { layout: {}, position: {} } - - for (let i = 0; i < component_array.length; i += 1) { - const { _styles, _id, _children } = component_array[i] - const { layout, position } = generate_css(_styles || emptyStyles) - - styles += apply_class(_id, "pos", position) + "\n" - styles += apply_class(_id, "lay", layout) + "\n" + 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 styles.trim() } + +export const generate_css = style => { + let cssString = Object.entries(style).reduce((str, [key, value]) => { + //TODO Handle arrays and objects here also + if (typeof value === "string") { + if (value) { + return (str += `${key}: ${value};\n`) + } + } else if (Array.isArray(value)) { + if (value.length > 0 && !value.every(v => v === "")) { + return (str += `${key}: ${value + .map(generate_array_styles) + .join(" ")};\n`) + } + } + }, "") + + return (cssString || "").trim() +} + +export const generate_array_styles = item => { + let safeItem = item === "" ? 0 : item + let hasPx = new RegExp("px$") + if (!hasPx.test(safeItem)) { + return `${safeItem}px` + } else { + return safeItem + } +} + +export 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}` + } +} diff --git a/packages/builder/src/builderStore/store/index.js b/packages/builder/src/builderStore/store/index.js index a8315918ba..f4d47064be 100644 --- a/packages/builder/src/builderStore/store/index.js +++ b/packages/builder/src/builderStore/store/index.js @@ -140,10 +140,11 @@ const _saveScreen = async (store, s, screen) => { return s } -const _saveScreenApi = (screen, s) => +const _saveScreenApi = (screen, s) => { api .post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen) .then(() => _savePage(s)) +} const createScreen = store => (screenName, route, layoutComponentName) => { store.update(state => { @@ -278,7 +279,6 @@ const removeStylesheet = store => stylesheet => { const _savePage = async s => { const page = s.pages[s.currentPageName] - await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, { page: { componentLibraries: s.pages.componentLibraries, ...page }, uiFunctions: s.currentPageFunctions, @@ -427,6 +427,7 @@ const setComponentStyle = store => (type, name, value) => { state.currentComponentInfo._styles = {} } state.currentComponentInfo._styles[type][name] = value + state.currentPreviewItem._css = generate_screen_css([ state.currentPreviewItem.props, ]) diff --git a/packages/builder/src/builderStore/store/workflow.js b/packages/builder/src/builderStore/store/workflow.js index 6ce68e2fa9..f1eb8b93f5 100644 --- a/packages/builder/src/builderStore/store/workflow.js +++ b/packages/builder/src/builderStore/store/workflow.js @@ -36,9 +36,10 @@ const workflowActions = store => ({ select: workflow => { store.update(state => { state.selectedWorkflowId = workflow._id + state.selectedWorkflowBlock = null return state; }) - } + } }); export const getWorkflowStore = () => { diff --git a/packages/builder/src/components/common/Colorpicker.svelte b/packages/builder/src/components/common/Colorpicker.svelte index 9cc3b3926a..8cff0e24bd 100644 --- a/packages/builder/src/components/common/Colorpicker.svelte +++ b/packages/builder/src/components/common/Colorpicker.svelte @@ -1,13 +1,78 @@ + +
+ A minimalist CRM which removes the noise and allows you to focus + on your business. +
+ +