Property panel updates

This commit is contained in:
Conor_Mack 2020-06-01 16:31:58 +01:00
parent 91b88ecad7
commit 93ab8659ed
8 changed files with 888 additions and 903 deletions

View File

@ -1,54 +1,42 @@
export const generate_screen_css = component_arr => {
let styles = ""
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])
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)
styles += apply_class(_id, componentName, cssString, selector);
}
})
});
if (_children && _children.length) {
styles += generate_screen_css(_children) + "\n"
styles += generate_screen_css(_children) + '\n';
}
}
return styles.trim()
}
return styles.trim();
};
export const generate_css = style => {
let cssString = Object.entries(style).reduce((str, [key, value]) => {
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 (typeof value === 'string') {
if (value) {
return (str += `${key}: ${value};\n`)
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`)
if (value.length > 0 && !value.every((v) => v === '')) {
return (str += `${key}: ${value.join(' ')};\n`);
}
}
}, "")
}, '');
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)) {
return `${safeItem}px`
export const apply_class = (id, name = 'element', styles, selector) => {
if (selector === 'normal') {
return `.${name}-${id} {\n${styles}\n}`;
} else {
return safeItem
let sel = selector === 'selected' ? '::selection' : `:${selector}`;
return `.${name}-${id}${sel} {\n${styles}\n}`;
}
}
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}`
}
}
};

View File

@ -1,321 +1,288 @@
import { cloneDeep, values } from "lodash/fp"
import { backendUiStore } from "builderStore"
import * as backendStoreActions from "./backend"
import { writable, get } from "svelte/store"
import api from "../api"
import { DEFAULT_PAGES_OBJECT } from "../../constants"
import { getExactComponent } from "components/userInterface/pagesParsing/searchComponents"
import { rename } from "components/userInterface/pagesParsing/renameScreen"
import {
createProps,
makePropsSafe,
getBuiltin,
} from "components/userInterface/pagesParsing/createProps"
import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
import { buildCodeForScreens } from "../buildCodeForScreens"
import { generate_screen_css } from "../generate_css"
import { insertCodeMetadata } from "../insertCodeMetadata"
import { uuid } from "../uuid"
import { cloneDeep, values } from 'lodash/fp';
import { backendUiStore } from 'builderStore';
import * as backendStoreActions from './backend';
import { writable, get } from 'svelte/store';
import api from '../api';
import { DEFAULT_PAGES_OBJECT } from '../../constants';
import { getExactComponent } from 'components/userInterface/pagesParsing/searchComponents';
import { rename } from 'components/userInterface/pagesParsing/renameScreen';
import { createProps, makePropsSafe, getBuiltin } from 'components/userInterface/pagesParsing/createProps';
import { fetchComponentLibDefinitions } from '../loadComponentLibraries';
import { buildCodeForScreens } from '../buildCodeForScreens';
import { generate_screen_css } from '../generate_css';
import { insertCodeMetadata } from '../insertCodeMetadata';
import { uuid } from '../uuid';
export const getStore = () => {
const initial = {
apps: [],
appname: "",
appname: '',
pages: DEFAULT_PAGES_OBJECT,
mainUi: {},
unauthenticatedUi: {},
components: [],
currentPreviewItem: null,
currentComponentInfo: null,
currentFrontEndType: "none",
currentPageName: "",
currentFrontEndType: 'none',
currentPageName: '',
currentComponentProps: null,
errors: [],
hasAppPackage: false,
libraries: null,
appId: "",
}
appId: ''
};
const store = writable(initial)
const store = writable(initial);
store.setPackage = setPackage(store, initial)
store.setPackage = setPackage(store, initial);
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store)
store.createDatabaseForApp = backendStoreActions.createDatabaseForApp(store);
store.saveScreen = saveScreen(store)
store.renameScreen = renameScreen(store)
store.deleteScreen = deleteScreen(store)
store.setCurrentScreen = setCurrentScreen(store)
store.setCurrentPage = setCurrentPage(store)
store.createScreen = createScreen(store)
store.addStylesheet = addStylesheet(store)
store.removeStylesheet = removeStylesheet(store)
store.savePage = savePage(store)
store.addChildComponent = addChildComponent(store)
store.selectComponent = selectComponent(store)
store.setComponentProp = setComponentProp(store)
store.setComponentStyle = setComponentStyle(store)
store.setComponentCode = setComponentCode(store)
store.setScreenType = setScreenType(store)
store.deleteComponent = deleteComponent(store)
store.moveUpComponent = moveUpComponent(store)
store.moveDownComponent = moveDownComponent(store)
store.copyComponent = copyComponent(store)
store.getPathToComponent = getPathToComponent(store)
store.addTemplatedComponent = addTemplatedComponent(store)
store.setMetadataProp = setMetadataProp(store)
return store
}
store.saveScreen = saveScreen(store);
store.renameScreen = renameScreen(store);
store.deleteScreen = deleteScreen(store);
store.setCurrentScreen = setCurrentScreen(store);
store.setCurrentPage = setCurrentPage(store);
store.createScreen = createScreen(store);
store.addStylesheet = addStylesheet(store);
store.removeStylesheet = removeStylesheet(store);
store.savePage = savePage(store);
store.addChildComponent = addChildComponent(store);
store.selectComponent = selectComponent(store);
store.setComponentProp = setComponentProp(store);
store.setComponentStyle = setComponentStyle(store);
store.setComponentCode = setComponentCode(store);
store.setScreenType = setScreenType(store);
store.deleteComponent = deleteComponent(store);
store.moveUpComponent = moveUpComponent(store);
store.moveDownComponent = moveDownComponent(store);
store.copyComponent = copyComponent(store);
store.getPathToComponent = getPathToComponent(store);
store.addTemplatedComponent = addTemplatedComponent(store);
store.setMetadataProp = setMetadataProp(store);
return store;
};
export default getStore
export default getStore;
const setPackage = (store, initial) => async pkg => {
const [main_screens, unauth_screens] = await Promise.all([
api
.get(`/_builder/api/${pkg.application._id}/pages/main/screens`)
.then(r => r.json()),
api
.get(`/_builder/api/${pkg.application._id}/pages/unauthenticated/screens`)
.then(r => r.json()),
])
const setPackage = (store, initial) => async (pkg) => {
const [ main_screens, unauth_screens ] = await Promise.all([
api.get(`/_builder/api/${pkg.application._id}/pages/main/screens`).then((r) => r.json()),
api.get(`/_builder/api/${pkg.application._id}/pages/unauthenticated/screens`).then((r) => r.json())
]);
pkg.pages = {
main: {
...pkg.pages.main,
_screens: Object.values(main_screens),
_screens: Object.values(main_screens)
},
unauthenticated: {
...pkg.pages.unauthenticated,
_screens: Object.values(unauth_screens),
},
_screens: Object.values(unauth_screens)
}
};
initial.libraries = pkg.application.componentLibraries
initial.components = await fetchComponentLibDefinitions(pkg.application._id)
initial.appname = pkg.application.name
initial.appId = pkg.application._id
initial.pages = pkg.pages
initial.hasAppPackage = true
initial.screens = values(pkg.screens)
initial.builtins = [getBuiltin("##builtin/screenslot")]
initial.appInstances = pkg.application.instances
initial.appId = pkg.application._id
initial.libraries = pkg.application.componentLibraries;
initial.components = await fetchComponentLibDefinitions(pkg.application._id);
initial.appname = pkg.application.name;
initial.appId = pkg.application._id;
initial.pages = pkg.pages;
initial.hasAppPackage = true;
initial.screens = values(pkg.screens);
initial.builtins = [ getBuiltin('##builtin/screenslot') ];
initial.appInstances = pkg.application.instances;
initial.appId = pkg.application._id;
store.set(initial)
return initial
}
store.set(initial);
return initial;
};
const saveScreen = store => screen => {
store.update(state => {
return _saveScreen(store, state, screen)
})
}
const saveScreen = (store) => (screen) => {
store.update((state) => {
return _saveScreen(store, state, screen);
});
};
const _saveScreen = async (store, s, screen) => {
const currentPageScreens = s.pages[s.currentPageName]._screens
const currentPageScreens = s.pages[s.currentPageName]._screens;
await api
.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen)
.then(() => {
if (currentPageScreens.includes(screen)) return
await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen).then(() => {
if (currentPageScreens.includes(screen)) return;
const screens = [...currentPageScreens, screen]
const screens = [ ...currentPageScreens, screen ];
store.update(innerState => {
innerState.pages[s.currentPageName]._screens = screens
innerState.screens = screens
innerState.currentPreviewItem = screen
const safeProps = makePropsSafe(
innerState.components[screen.props._component],
screen.props
)
innerState.currentComponentInfo = safeProps
screen.props = safeProps
store.update((innerState) => {
innerState.pages[s.currentPageName]._screens = screens;
innerState.screens = screens;
innerState.currentPreviewItem = screen;
const safeProps = makePropsSafe(innerState.components[screen.props._component], screen.props);
innerState.currentComponentInfo = safeProps;
screen.props = safeProps;
_savePage(innerState)
return innerState
})
})
_savePage(innerState);
return innerState;
});
});
return s
}
return s;
};
const _saveScreenApi = (screen, s) => {
api
.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen)
.then(() => _savePage(s))
}
api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}/screen`, screen).then(() => _savePage(s));
};
const createScreen = store => (screenName, route, layoutComponentName) => {
store.update(state => {
const rootComponent = state.components[layoutComponentName]
const createScreen = (store) => (screenName, route, layoutComponentName) => {
store.update((state) => {
const rootComponent = state.components[layoutComponentName];
const newScreen = {
name: screenName || "",
description: "",
url: "",
_css: "",
uiFunctions: "",
props: createProps(rootComponent).props,
}
name: screenName || '',
description: '',
url: '',
_css: '',
uiFunctions: '',
props: createProps(rootComponent).props
};
newScreen.route = route
state.currentPreviewItem = newScreen
state.currentComponentInfo = newScreen.props
state.currentFrontEndType = "screen"
newScreen.route = route;
state.currentPreviewItem = newScreen;
state.currentComponentInfo = newScreen.props;
state.currentFrontEndType = 'screen';
_saveScreen(store, state, newScreen)
_saveScreen(store, state, newScreen);
return state
})
}
return state;
});
};
const setCurrentScreen = store => screenName => {
store.update(s => {
const screen = getExactComponent(s.screens, screenName)
screen._css = generate_screen_css([screen.props])
s.currentPreviewItem = screen
s.currentFrontEndType = "screen"
s.currentView = "detail"
const setCurrentScreen = (store) => (screenName) => {
store.update((s) => {
const screen = getExactComponent(s.screens, screenName);
screen._css = generate_screen_css([ screen.props ]);
s.currentPreviewItem = screen;
s.currentFrontEndType = 'screen';
s.currentView = 'detail';
const safeProps = makePropsSafe(
s.components[screen.props._component],
screen.props
)
screen.props = safeProps
s.currentComponentInfo = safeProps
setCurrentPageFunctions(s)
return s
})
}
const safeProps = makePropsSafe(s.components[screen.props._component], screen.props);
screen.props = safeProps;
s.currentComponentInfo = safeProps;
setCurrentPageFunctions(s);
return s;
});
};
const deleteScreen = store => name => {
store.update(s => {
const components = s.components.filter(c => c.name !== name)
const screens = s.screens.filter(c => c.name !== name)
const deleteScreen = (store) => (name) => {
store.update((s) => {
const components = s.components.filter((c) => c.name !== name);
const screens = s.screens.filter((c) => c.name !== name);
s.components = components
s.screens = screens
s.components = components;
s.screens = screens;
if (s.currentPreviewItem.name === name) {
s.currentPreviewItem = null
s.currentFrontEndType = ""
s.currentPreviewItem = null;
s.currentFrontEndType = '';
}
api.delete(`/_builder/api/${s.appId}/screen/${name}`)
api.delete(`/_builder/api/${s.appId}/screen/${name}`);
return s
})
}
return s;
});
};
const renameScreen = store => (oldname, newname) => {
store.update(s => {
const { screens, pages, error, changedScreens } = rename(
s.pages,
s.screens,
oldname,
newname
)
const renameScreen = (store) => (oldname, newname) => {
store.update((s) => {
const { screens, pages, error, changedScreens } = rename(s.pages, s.screens, oldname, newname);
if (error) {
// should really do something with this
return s
return s;
}
s.screens = screens
s.pages = pages
if (s.currentPreviewItem.name === oldname)
s.currentPreviewItem.name = newname
s.screens = screens;
s.pages = pages;
if (s.currentPreviewItem.name === oldname) s.currentPreviewItem.name = newname;
const saveAllChanged = async () => {
for (let screenName of changedScreens) {
const changedScreen = getExactComponent(screens, screenName)
await api.post(`/_builder/api/${s.appId}/screen`, changedScreen)
}
const changedScreen = getExactComponent(screens, screenName);
await api.post(`/_builder/api/${s.appId}/screen`, changedScreen);
}
};
api
.patch(`/_builder/api/${s.appId}/screen`, {
oldname,
newname,
newname
})
.then(() => saveAllChanged())
.then(() => {
_savePage(s)
})
_savePage(s);
});
return s
})
}
return s;
});
};
const savePage = store => async page => {
store.update(state => {
if (state.currentFrontEndType !== "page" || !state.currentPageName) {
return state
const savePage = (store) => async (page) => {
store.update((state) => {
if (state.currentFrontEndType !== 'page' || !state.currentPageName) {
return state;
}
state.pages[state.currentPageName] = page
_savePage(state)
return state
})
}
state.pages[state.currentPageName] = page;
_savePage(state);
return state;
});
};
const addStylesheet = store => stylesheet => {
store.update(s => {
s.pages.stylesheets.push(stylesheet)
_savePage(s)
return s
})
}
const addStylesheet = (store) => (stylesheet) => {
store.update((s) => {
s.pages.stylesheets.push(stylesheet);
_savePage(s);
return s;
});
};
const removeStylesheet = store => stylesheet => {
store.update(state => {
state.pages.stylesheets = state.pages.stylesheets.filter(
s => s !== stylesheet
)
_savePage(state)
return state
})
}
const removeStylesheet = (store) => (stylesheet) => {
store.update((state) => {
state.pages.stylesheets = state.pages.stylesheets.filter((s) => s !== stylesheet);
_savePage(state);
return state;
});
};
const _savePage = async s => {
const page = s.pages[s.currentPageName]
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,
screens: page._screens,
})
}
screens: page._screens
});
};
const setCurrentPage = store => pageName => {
store.update(state => {
const current_screens = state.pages[pageName]._screens
const setCurrentPage = (store) => (pageName) => {
store.update((state) => {
const current_screens = state.pages[pageName]._screens;
const currentPage = state.pages[pageName]
const currentPage = state.pages[pageName];
state.currentFrontEndType = "page"
state.currentPageName = pageName
state.screens = Array.isArray(current_screens)
? current_screens
: Object.values(current_screens)
const safeProps = makePropsSafe(
state.components[currentPage.props._component],
currentPage.props
)
state.currentComponentInfo = safeProps
currentPage.props = safeProps
state.currentPreviewItem = state.pages[pageName]
state.currentPreviewItem._css = generate_screen_css([
state.currentPreviewItem.props,
])
state.currentFrontEndType = 'page';
state.currentPageName = pageName;
state.screens = Array.isArray(current_screens) ? current_screens : Object.values(current_screens);
const safeProps = makePropsSafe(state.components[currentPage.props._component], currentPage.props);
state.currentComponentInfo = safeProps;
currentPage.props = safeProps;
state.currentPreviewItem = state.pages[pageName];
state.currentPreviewItem._css = generate_screen_css([ state.currentPreviewItem.props ]);
for (let screen of state.screens) {
screen._css = generate_screen_css([screen.props])
screen._css = generate_screen_css([ screen.props ]);
}
setCurrentPageFunctions(state)
return state
})
}
setCurrentPageFunctions(state);
return state;
});
};
// const getComponentDefinition = (components, name) => components.find(c => c.name === name)
@ -323,288 +290,267 @@ const setCurrentPage = store => pageName => {
* @param {string} componentToAdd - name of the component to add to the application
* @param {string} presetName - name of the component preset if defined
*/
const addChildComponent = store => (componentToAdd, presetName) => {
store.update(state => {
const addChildComponent = (store) => (componentToAdd, presetName) => {
store.update((state) => {
function findSlot(component_array) {
for (let i = 0; i < component_array.length; i += 1) {
if (component_array[i]._component === "##builtin/screenslot") {
return true
if (component_array[i]._component === '##builtin/screenslot') {
return true;
}
if (component_array[i]._children) findSlot(component_array[i])
if (component_array[i]._children) findSlot(component_array[i]);
}
return false
return false;
}
if (
componentToAdd.startsWith("##") &&
findSlot(state.pages[state.currentPageName].props._children)
) {
return state
if (componentToAdd.startsWith('##') && findSlot(state.pages[state.currentPageName].props._children)) {
return state;
}
const component = componentToAdd.startsWith("##")
const component = componentToAdd.startsWith('##')
? getBuiltin(componentToAdd)
: state.components[componentToAdd]
: state.components[componentToAdd];
const presetProps = presetName ? component.presets[presetName] : {}
const presetProps = presetName ? component.presets[presetName] : {};
const instanceId = get(backendUiStore).selectedDatabase._id
const instanceId = get(backendUiStore).selectedDatabase._id;
const newComponent = createProps(
component,
{
...presetProps,
_instanceId: instanceId,
_instanceId: instanceId
},
state
)
);
state.currentComponentInfo._children = state.currentComponentInfo._children.concat(
newComponent.props
)
state.currentComponentInfo._children = state.currentComponentInfo._children.concat(newComponent.props);
state.currentFrontEndType === "page"
? _savePage(state)
: _saveScreenApi(state.currentPreviewItem, state)
state.currentFrontEndType === 'page' ? _savePage(state) : _saveScreenApi(state.currentPreviewItem, state);
state.currentView = "component"
state.currentComponentInfo = newComponent.props
state.currentView = 'component';
state.currentComponentInfo = newComponent.props;
return state
})
}
return state;
});
};
/**
* @param {string} props - props to add, as child of current component
*/
const addTemplatedComponent = store => props => {
store.update(state => {
walkProps(props, p => {
p._id = uuid()
})
state.currentComponentInfo._children = state.currentComponentInfo._children.concat(
props
)
state.currentPreviewItem._css = generate_screen_css([
state.currentPreviewItem.props,
])
const addTemplatedComponent = (store) => (props) => {
store.update((state) => {
walkProps(props, (p) => {
p._id = uuid();
});
state.currentComponentInfo._children = state.currentComponentInfo._children.concat(props);
state.currentPreviewItem._css = generate_screen_css([ state.currentPreviewItem.props ]);
setCurrentPageFunctions(state)
_saveCurrentPreviewItem(state)
setCurrentPageFunctions(state);
_saveCurrentPreviewItem(state);
return state
})
}
return state;
});
};
const selectComponent = store => component => {
store.update(state => {
const componentDef = component._component.startsWith("##")
? component
: state.components[component._component]
state.currentComponentInfo = makePropsSafe(componentDef, component)
state.currentView = "component"
return state
})
}
const selectComponent = (store) => (component) => {
store.update((state) => {
const componentDef = component._component.startsWith('##') ? component : state.components[component._component];
state.currentComponentInfo = makePropsSafe(componentDef, component);
state.currentView = 'component';
return state;
});
};
const setComponentProp = store => (name, value) => {
store.update(state => {
const current_component = state.currentComponentInfo
state.currentComponentInfo[name] = value
const setComponentProp = (store) => (name, value) => {
store.update((state) => {
const current_component = state.currentComponentInfo;
state.currentComponentInfo[name] = value;
_saveCurrentPreviewItem(state)
_saveCurrentPreviewItem(state);
state.currentComponentInfo = current_component
return state
})
}
state.currentComponentInfo = current_component;
return state;
});
};
const setComponentStyle = store => (type, name, value) => {
store.update(state => {
const setComponentStyle = (store) => (type, name, value) => {
store.update((state) => {
if (!state.currentComponentInfo._styles) {
state.currentComponentInfo._styles = {}
state.currentComponentInfo._styles = {};
}
state.currentComponentInfo._styles[type][name] = value
state.currentComponentInfo._styles[type][name] = value;
state.currentPreviewItem._css = generate_screen_css([
state.currentPreviewItem.props,
])
state.currentPreviewItem._css = generate_screen_css([ state.currentPreviewItem.props ]);
// save without messing with the store
_saveCurrentPreviewItem(state)
return state
})
}
_saveCurrentPreviewItem(state);
return state;
});
};
const setComponentCode = store => code => {
store.update(state => {
state.currentComponentInfo._code = code
const setComponentCode = (store) => (code) => {
store.update((state) => {
state.currentComponentInfo._code = code;
setCurrentPageFunctions(state)
setCurrentPageFunctions(state);
// save without messing with the store
_saveScreenApi(state.currentPreviewItem, state)
_saveScreenApi(state.currentPreviewItem, state);
return state
})
}
return state;
});
};
const setCurrentPageFunctions = s => {
s.currentPageFunctions = buildPageCode(s.screens, s.pages[s.currentPageName])
insertCodeMetadata(s.currentPreviewItem.props)
}
const setCurrentPageFunctions = (s) => {
s.currentPageFunctions = buildPageCode(s.screens, s.pages[s.currentPageName]);
insertCodeMetadata(s.currentPreviewItem.props);
};
const buildPageCode = (screens, page) => buildCodeForScreens([page, ...screens])
const buildPageCode = (screens, page) => buildCodeForScreens([ page, ...screens ]);
const setScreenType = store => type => {
store.update(state => {
state.currentFrontEndType = type
const setScreenType = (store) => (type) => {
store.update((state) => {
state.currentFrontEndType = type;
const pageOrScreen =
type === "page"
? state.pages[state.currentPageName]
: state.pages[state.currentPageName]._screens[0]
type === 'page' ? state.pages[state.currentPageName] : state.pages[state.currentPageName]._screens[0];
state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null
state.currentPreviewItem = pageOrScreen
return state
})
}
state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null;
state.currentPreviewItem = pageOrScreen;
return state;
});
};
const deleteComponent = store => componentName => {
store.update(state => {
const parent = getParent(state.currentPreviewItem.props, componentName)
const deleteComponent = (store) => (componentName) => {
store.update((state) => {
const parent = getParent(state.currentPreviewItem.props, componentName);
if (parent) {
parent._children = parent._children.filter(
component => component !== componentName
)
parent._children = parent._children.filter((component) => component !== componentName);
}
_saveCurrentPreviewItem(state)
_saveCurrentPreviewItem(state);
return state
})
}
return state;
});
};
const moveUpComponent = store => component => {
store.update(s => {
const parent = getParent(s.currentPreviewItem.props, component)
const moveUpComponent = (store) => (component) => {
store.update((s) => {
const parent = getParent(s.currentPreviewItem.props, component);
if (parent) {
const currentIndex = parent._children.indexOf(component)
if (currentIndex === 0) return s
const currentIndex = parent._children.indexOf(component);
if (currentIndex === 0) return s;
const newChildren = parent._children.filter(c => c !== component)
newChildren.splice(currentIndex - 1, 0, component)
parent._children = newChildren
const newChildren = parent._children.filter((c) => c !== component);
newChildren.splice(currentIndex - 1, 0, component);
parent._children = newChildren;
}
s.currentComponentInfo = component
_saveCurrentPreviewItem(s)
s.currentComponentInfo = component;
_saveCurrentPreviewItem(s);
return s
})
}
return s;
});
};
const moveDownComponent = store => component => {
store.update(s => {
const parent = getParent(s.currentPreviewItem.props, component)
const moveDownComponent = (store) => (component) => {
store.update((s) => {
const parent = getParent(s.currentPreviewItem.props, component);
if (parent) {
const currentIndex = parent._children.indexOf(component)
if (currentIndex === parent._children.length - 1) return s
const currentIndex = parent._children.indexOf(component);
if (currentIndex === parent._children.length - 1) return s;
const newChildren = parent._children.filter(c => c !== component)
newChildren.splice(currentIndex + 1, 0, component)
parent._children = newChildren
const newChildren = parent._children.filter((c) => c !== component);
newChildren.splice(currentIndex + 1, 0, component);
parent._children = newChildren;
}
s.currentComponentInfo = component
_saveCurrentPreviewItem(s)
s.currentComponentInfo = component;
_saveCurrentPreviewItem(s);
return s
})
}
return s;
});
};
const copyComponent = store => component => {
store.update(s => {
const parent = getParent(s.currentPreviewItem.props, component)
const copiedComponent = cloneDeep(component)
walkProps(copiedComponent, p => {
p._id = uuid()
})
parent._children = [...parent._children, copiedComponent]
s.curren
_saveCurrentPreviewItem(s)
s.currentComponentInfo = copiedComponent
return s
})
}
const copyComponent = (store) => (component) => {
store.update((s) => {
const parent = getParent(s.currentPreviewItem.props, component);
const copiedComponent = cloneDeep(component);
walkProps(copiedComponent, (p) => {
p._id = uuid();
});
parent._children = [ ...parent._children, copiedComponent ];
s.curren;
_saveCurrentPreviewItem(s);
s.currentComponentInfo = copiedComponent;
return s;
});
};
const getPathToComponent = store => component => {
const getPathToComponent = (store) => (component) => {
// Gets all the components to needed to construct a path.
const tempStore = get(store)
let pathComponents = []
let parent = component
let root = false
const tempStore = get(store);
let pathComponents = [];
let parent = component;
let root = false;
while (!root) {
parent = getParent(tempStore.currentPreviewItem.props, parent)
parent = getParent(tempStore.currentPreviewItem.props, parent);
if (!parent) {
root = true
root = true;
} else {
pathComponents.push(parent)
pathComponents.push(parent);
}
}
// Remove root entry since it's the screen or page layout.
// Reverse array since we need the correct order of the IDs
const reversedComponents = pathComponents.reverse().slice(1)
const reversedComponents = pathComponents.reverse().slice(1);
// Add component
const allComponents = [...reversedComponents, component]
const allComponents = [ ...reversedComponents, component ];
// Map IDs
const IdList = allComponents.map(c => c._id)
const IdList = allComponents.map((c) => c._id);
// Construct ID Path:
const path = IdList.join("/")
const path = IdList.join('/');
return path
}
return path;
};
const getParent = (rootProps, child) => {
let parent
let parent;
walkProps(rootProps, (p, breakWalk) => {
if (p._children && p._children.includes(child)) {
parent = p
breakWalk()
parent = p;
breakWalk();
}
})
return parent
}
});
return parent;
};
const walkProps = (props, action, cancelToken = null) => {
cancelToken = cancelToken || { cancelled: false }
cancelToken = cancelToken || { cancelled: false };
action(props, () => {
cancelToken.cancelled = true
})
cancelToken.cancelled = true;
});
if (props._children) {
for (let child of props._children) {
if (cancelToken.cancelled) return
walkProps(child, action, cancelToken)
if (cancelToken.cancelled) return;
walkProps(child, action, cancelToken);
}
}
}
};
const setMetadataProp = store => (name, prop) => {
store.update(s => {
s.currentPreviewItem[name] = prop
return s
})
}
const setMetadataProp = (store) => (name, prop) => {
store.update((s) => {
s.currentPreviewItem[name] = prop;
return s;
});
};
const _saveCurrentPreviewItem = s =>
s.currentFrontEndType === "page"
? _savePage(s)
: _saveScreenApi(s.currentPreviewItem, s)
const _saveCurrentPreviewItem = (s) =>
s.currentFrontEndType === 'page' ? _savePage(s) : _saveScreenApi(s.currentPreviewItem, s);

View File

@ -1,14 +1,17 @@
<script>
import {buildStyle} from "../../helpers.js"
import {onMount} from "svelte"
import { buildStyle } from "../../helpers.js"
export let value = ""
export let textAlign = "left"
export let width = "160px"
export let placeholder = ""
let centerPlaceholder = textAlign === "center"
let style = buildStyle({ width, textAlign })
</script>
<input type="text" {placeholder} {style} on:change bind:value />
<input class:centerPlaceholder type="text" {placeholder} {style} on:change bind:value />
<style>
input {
@ -24,10 +27,13 @@
border: 1px solid var(--grey);
border-radius: 2px;
outline: none;
float: right;
}
input::placeholder {
text-align: left;
}
.centerPlaceholder::placeholder {
text-align: center;
}
</style>

View File

@ -5,40 +5,41 @@
export let meta = []
export let label = ""
export let value = ["0", "0", "0", "0"]
export let type = "number"
export let suffix = ""
export let onChange = () => {}
function handleChange(val, idx) {
value.splice(idx, 1, val)
value.splice(idx, 1, suffix ? val + suffix : val)
value = value
console.log("IDX",idx)
let _value = value.map(v => !/px$/.test(v) ? `${v}px` : v)
let _value = value.map(v => (!v.endsWith(suffix) ? v + suffix : v))
onChange(_value)
}
$: displayValues = value.map(v => v.toString().replace(/px$/, ""))
$: displayValues = value
? value.map(v => v.replace(new RegExp(`${suffix}$`), ""))
: []
</script>
<div class="input-container">
<div class="label">{label}</div>
<div class="inputs">
{#each meta as { placeholder }, i}
<Input width="32px" textAlign="center" placeholder={placeholder || ""} value={!displayValues || displayValues[i] === 0 ? '' : displayValues[i]} on:change={e => handleChange(e.target.value || 0, i)} />
<div class="inputs-group">
{#each meta as m, i}
<Input
width="32px"
textAlign="center"
placeholder={m.placeholder || ''}
value={!displayValues || displayValues[i] === '0' ? '' : displayValues[i]}
on:change={e => handleChange(e.target.value || 0, i)} />
{/each}
</div>
</div>
<style>
.label {
flex: 0;
}
.inputs {
.inputs-group {
flex: 1;
}
</style>

View File

@ -3,7 +3,7 @@
export let value = ""
export let text = ""
export let icon = ""
export let padding = "8px 2px;"
export let padding = "8px 5px;"
export let onClick = value => {}
export let selected = false
export let fontWeight = ""

View File

@ -28,9 +28,9 @@
onChange(val)
}
const checkSelected = val => isMultiSelect ? value.includes(val) : value === val
const checkSelected = val =>
isMultiSelect ? value.includes(val) : value === val
$: console.log("VALUE",value)
</script>
<div class="flatbutton-group">

View File

@ -144,6 +144,7 @@
width: 160px;
height: 32px;
cursor: pointer;
font-size: 12px;
}
.bb-select-anchor {
@ -153,6 +154,7 @@
background-color: #f2f2f2;
border-radius: 2px;
border: 1px solid var(--grey-dark);
align-items: center;
}
.bb-select-anchor > span {

View File

@ -1,7 +1,7 @@
import Input from "../common/Input.svelte"
import OptionSelect from "./OptionSelect.svelte"
import InputGroup from "../common/Inputs/InputGroup.svelte"
import FlatButtonGroup from "./FlatButtonGroup.svelte"
import Input from '../common/Input.svelte';
import OptionSelect from './OptionSelect.svelte';
import InputGroup from '../common/Inputs/InputGroup.svelte';
import FlatButtonGroup from './FlatButtonGroup.svelte';
// import Colorpicker from "../common/Colorpicker.svelte"
/*
TODO: Allow for default values for all properties
@ -9,338 +9,380 @@ import FlatButtonGroup from "./FlatButtonGroup.svelte"
export const layout = [
{
label: "Display",
key: "display",
label: 'Display',
key: 'display',
control: OptionSelect,
initialValue: "Flex",
options: [
{ label: "Flex", value: "flex" },
{ label: "Inline Flex", value: "inline-flex" },
],
initialValue: 'Flex',
options: [ { label: 'Flex', value: 'flex' }, { label: 'Inline Flex', value: 'inline-flex' } ]
},
{
label: "Direction",
key: "flex-direction",
label: 'Direction',
key: 'flex-direction',
control: FlatButtonGroup,
buttonProps: [
{ icon: "ri-arrow-right-line", padding: "4px 8px", value: "row" },
{ icon: "ri-arrow-left-line", padding: "4px 8px", value: "rowReverse" },
{ icon: "ri-arrow-down-line", padding: "4px 8px", value: "column" },
{ icon: 'ri-arrow-right-line', padding: '0px 5px', value: 'row' },
{ icon: 'ri-arrow-left-line', padding: '0px 5px', value: 'rowReverse' },
{ icon: 'ri-arrow-down-line', padding: '0px 5px', value: 'column' },
{
icon: "ri-arrow-up-line",
padding: "4px 8px",
value: "columnReverse",
},
],
icon: 'ri-arrow-up-line',
padding: '0px 5px',
value: 'columnReverse'
}
]
},
{
label: "Justify",
key: "justify-content",
label: 'Justify',
key: 'justify-content',
control: OptionSelect,
initialValue: "Flex Start",
initialValue: 'Flex Start',
options: [
{ label: "Flex Start", value: "flex-start" },
{ label: "Flex End", value: "flex-end" },
{ label: "Center", value: "center" },
{ label: "Space Between", value: "space-between" },
{ label: "Space Around", value: "space-around" },
{ label: "Space Evenly", value: "space-evenly" },
],
{ label: 'Flex Start', value: 'flex-start' },
{ label: 'Flex End', value: 'flex-end' },
{ label: 'Center', value: 'center' },
{ label: 'Space Between', value: 'space-between' },
{ label: 'Space Around', value: 'space-around' },
{ label: 'Space Evenly', value: 'space-evenly' }
]
},
{
label: "Align",
key: "align-items",
label: 'Align',
key: 'align-items',
control: OptionSelect,
initialValue: "Flex Start",
initialValue: 'Flex Start',
options: [
{ label: "Flex Start", value: "flex-start" },
{ label: "Flex End", value: "flex-end" },
{ label: "Center", value: "center" },
{ label: "Baseline", value: "baseline" },
{ label: "Stretch", value: "stretch" },
],
{ label: 'Flex Start', value: 'flex-start' },
{ label: 'Flex End', value: 'flex-end' },
{ label: 'Center', value: 'center' },
{ label: 'Baseline', value: 'baseline' },
{ label: 'Stretch', value: 'stretch' }
]
},
{
label: "Wrap",
key: "flex-wrap",
label: 'Wrap',
key: 'flex-wrap',
control: OptionSelect,
options: [
{ label: "wrap", value: "wrap" },
{ label: "no wrap", value: "noWrap" },
],
},
]
options: [ { label: 'wrap', value: 'wrap' }, { label: 'no wrap', value: 'noWrap' } ]
}
];
const spacingMeta = [
{ placeholder: "&#8593;" },
{ placeholder: "&#8594;" },
{ placeholder: "&#8595;" },
{ placeholder: "&#8592;" },
]
const spacingMeta = [ { placeholder: 'T' }, { placeholder: 'R' }, { placeholder: 'B' }, { placeholder: 'L' } ];
export const spacing = [
{ label: "Margin", key: "margin", control: InputGroup, meta: spacingMeta },
{
label: "Padding",
key: "padding",
label: 'Margin',
key: 'margin',
control: InputGroup,
meta: spacingMeta,
suffix: 'px',
defaultValue: [ '0', '0', '0', '0' ]
},
]
{
label: 'Padding',
key: 'padding',
control: InputGroup,
meta: spacingMeta,
suffix: 'px',
defaultValue: [ '0', '0', '0', '0' ]
}
];
export const size = [
{
label: "Width",
key: "width",
label: 'Width',
key: 'width',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Height",
key: "height",
label: 'Height',
key: 'height',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Min W",
key: "min-width",
label: 'Min W',
key: 'min-width',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Min H",
key: "min-height",
label: 'Min H',
key: 'min-height',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Max W",
key: "max-width",
label: 'Max W',
key: 'max-width',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Max H",
key: "max-height",
label: 'Max H',
key: 'max-height',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
},
]
placeholder: 'px',
width: '48px',
textAlign: 'center'
}
];
export const position = [
{
label: "Position",
key: "position",
label: 'Position',
key: 'position',
control: OptionSelect,
initialValue: "Wrap",
initialValue: 'Wrap',
options: [
{ label: "Static", value: "static" },
{ label: "Relative", value: "relative" },
{ label: "Fixed", value: "fixed" },
{ label: "Absolute", value: "absolute" },
{ label: "Sticky", value: "sticky" },
],
{ label: 'Static', value: 'static' },
{ label: 'Relative', value: 'relative' },
{ label: 'Fixed', value: 'fixed' },
{ label: 'Absolute', value: 'absolute' },
{ label: 'Sticky', value: 'sticky' }
]
},
{
label: "Top",
key: "top",
label: 'Top',
key: 'top',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Right",
key: "right",
label: 'Right',
key: 'right',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Bottom",
key: "bottom",
label: 'Bottom',
key: 'bottom',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Left",
key: "left",
label: 'Left',
key: 'left',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Z-index",
key: "z-index",
label: 'Z-index',
key: 'z-index',
control: Input,
placeholder: "Num",
width: "48px",
textAlign: "center",
},
]
placeholder: 'num',
width: '48px',
textAlign: 'center'
}
];
export const typography = [
{
label: "Font",
key: "font-family",
label: 'Font',
key: 'font-family',
control: OptionSelect,
defaultValue: "initial",
defaultValue: 'initial',
options: [
"initial",
"Arial",
"Arial Black",
"Cursive",
"Courier",
"Comic Sans MS",
"Helvetica",
"Impact",
"Inter",
"Lucida Sans Unicode",
"Open Sans",
"Playfair",
"Roboto",
"Roboto Mono",
"Times New Roman",
"Verdana",
'initial',
'Arial',
'Arial Black',
'Cursive',
'Courier',
'Comic Sans MS',
'Helvetica',
'Impact',
'Inter',
'Lucida Sans Unicode',
'Open Sans',
'Playfair',
'Roboto',
'Roboto Mono',
'Times New Roman',
'Verdana'
],
styleBindingProperty: "font-family",
styleBindingProperty: 'font-family'
},
{
label: "Weight",
key: "font-weight",
label: 'Weight',
key: 'font-weight',
control: OptionSelect,
options: ["normal", "bold", "bolder", "lighter"],
options: [ 'normal', 'bold', 'bolder', 'lighter' ]
},
{
label: "size",
key: "font-size",
defaultValue: "",
label: 'size',
key: 'font-size',
defaultValue: '',
control: Input,
placeholder: "px",
width: "48px",
textAlign: "center",
placeholder: 'px',
width: '48px',
textAlign: 'center'
},
{
label: "Line H",
key: "line-height",
label: 'Line H',
key: 'line-height',
control: Input,
placeholder: "lh",
width: "48px",
textAlign: "center",
placeholder: 'lh',
width: '48px',
textAlign: 'center'
},
{
label: "Color",
key: "color",
label: 'Color',
key: 'color',
control: Input,
placeholder: "hex",
},
{
label: "align",
key: "text-align",
label: 'align',
key: 'text-align',
control: FlatButtonGroup,
buttonProps: [
{ icon: "ri-align-left", padding: "4px 8px", value: "left" },
{ icon: "ri-align-center", padding: "4px 8px", value: "center" },
{ icon: "ri-align-right", padding: "4px 8px", value: "right" },
{ icon: "ri-align-justify", padding: "4px 8px", value: "justify" },
],
{ icon: 'ri-align-left', padding: '0px 5px', value: 'left' },
{ icon: 'ri-align-center', padding: '0px 5px', value: 'center' },
{ icon: 'ri-align-right', padding: '0px 5px', value: 'right' },
{ icon: 'ri-align-justify', padding: '0px 5px', value: 'justify' }
]
},
{
label: "transform",
key: "text-transform",
label: 'transform',
key: 'text-transform',
control: FlatButtonGroup,
buttonProps: [
{ text: "BB", padding: "4px 8px", fontWeight: 500, value: "uppercase" },
{ text: "Bb", padding: "4px 8px", fontWeight: 500, value: "capitalize" },
{ text: "bb", padding: "4px 8px", fontWeight: 500, value: "lowercase" },
{ 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: "4px 8px",
text: '&times;',
padding: '0px 5px',
fontWeight: 500,
value: "none",
value: 'none'
}
]
},
],
},
{ label: "style", key: "font-style", control: Input },
]
{ label: 'style', key: 'font-style', control: Input }
];
export const background = [
{
label: "Background",
key: "background",
label: 'Background',
key: 'background',
control: Input,
},
{ label: "Image", key: "image", control: Input }, //custom
]
{
label: "Image",
key: "background-image",
control: Input,
placeholder: "src",
},
];
export const border = [
{ label: "Radius", key: "border-radius", control: Input },
{ label: "Width", key: "border-width", control: Input }, //custom
{
label: "Color",
key: "border-color",
label: 'Radius',
key: 'border-radius',
control: Input,
width: '48px',
placeholder: 'px',
textAlign: 'center'
},
{
label: "Style",
key: "border-style",
control: OptionSelect,
options: [
"none",
"hidden",
"dotted",
"dashed",
"solid",
"double",
"groove",
"ridge",
"inset",
"outset",
],
label: 'Width',
key: 'border-width',
control: Input,
width: '48px',
placeholder: 'px',
textAlign: 'center'
}, //custom
{
label: 'Color',
key: 'border-color',
control: Input
},
]
{
label: 'Style',
key: 'border-style',
control: OptionSelect,
options: [ 'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset' ]
}
];
export const effects = [
{ label: "Opacity", key: "opacity", control: Input },
{
label: "Rotate",
key: "transform",
control: OptionSelect,
options: [
{ label: "None", value: "rotate(0deg)" },
{ label: "45 degrees", value: "rotate(45deg)" },
{ 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)" },
],
label: 'Opacity',
key: 'opacity',
control: Input,
width: '48px',
textAlign: 'center',
placeholder: '%'
},
{
label: 'Rotate',
key: 'transform',
control: Input,
width: '48px',
textAlign: 'center',
placeholder: 'deg'
}, //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 = [
{ label: "Property", key: "transition-property", control: Input },
{ label: "Duration", key: "transition-timing-function", control: Input },
{ label: "Ease", key: "transition-ease", control: Input },
]
{
label: 'Property',
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 = {
layout,
@ -351,15 +393,15 @@ export const all = {
background,
border,
effects,
transitions,
}
transitions
};
export function excludeProps(props, propsToExclude) {
const modifiedProps = {}
const modifiedProps = {};
for (const prop in props) {
if (!propsToExclude.includes(prop)) {
modifiedProps[prop] = props[prop]
modifiedProps[prop] = props[prop];
}
}
return modifiedProps
return modifiedProps;
}