mirror of https://github.com/Budibase/budibase.git
Browse Source
* refactoring server for screens & page layout restructure * Disable API calls, UI placeholders. * buildPropsHierarchy is gone & screen has url * Recent changes. * router * router * updated git-ignore to reinclude server/utilities/builder * modified cli - budi new create new file structure * Fix uuid import. * prettier fixes * prettier fixes * prettier fixes * page/screen restructure.. broken tests * all tests passing at last * screen routing tests * Working screen editor and preview. * Render page previews to the screen. * Key input lists to ensure new array references when updating styles. * Ensure the iframe html and body fills the container. * Save screens via the API. * Get all save APIs almost working. * Write pages.json to disk. * Use correct API endpoint for saving styles. * Differentiate between saving properties of screens and pages. * Add required fields to default pages layouts. * Add _css default property to newly created screens. * Add default code property. * page layout / screens - app output Co-authored-by: pngwn <pnda007@gmail.com>pull/4023/head
committed by
GitHub
98 changed files with 135578 additions and 176997 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,3 @@ |
|||
<script> |
|||
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte" |
|||
</script> |
|||
@ -1,57 +0,0 @@ |
|||
import { getComponentInfo, createProps, getInstanceProps } from "./createProps" |
|||
|
|||
export const buildPropsHierarchy = (components, screens, baseComponent) => { |
|||
const allComponents = [...components, ...screens] |
|||
|
|||
const buildProps = (componentDefinition, derivedFromProps) => { |
|||
const { props } = createProps(componentDefinition, derivedFromProps) |
|||
const propsDefinition = componentDefinition.props |
|||
props._component = componentDefinition.name |
|||
for (let propName in props) { |
|||
if (propName === "_component") continue |
|||
|
|||
const propDef = propsDefinition[propName] |
|||
if (!propDef) continue |
|||
if (propName === "_children") { |
|||
const childrenProps = props[propName] |
|||
|
|||
if (!childrenProps || childrenProps.length === 0) { |
|||
continue |
|||
} |
|||
|
|||
props[propName] = [] |
|||
|
|||
for (let child of childrenProps) { |
|||
const propComponentInfo = getComponentInfo( |
|||
allComponents, |
|||
child._component |
|||
) |
|||
|
|||
const subComponentInstanceProps = getInstanceProps( |
|||
propComponentInfo, |
|||
child |
|||
) |
|||
|
|||
props[propName].push( |
|||
buildProps( |
|||
propComponentInfo.rootComponent.name, |
|||
propComponentInfo.propsDefinition, |
|||
subComponentInstanceProps |
|||
) |
|||
) |
|||
} |
|||
} |
|||
} |
|||
|
|||
return props |
|||
} |
|||
|
|||
if (!baseComponent) return {} |
|||
|
|||
const baseComponentInfo = getComponentInfo(allComponents, baseComponent) |
|||
|
|||
return buildProps( |
|||
baseComponentInfo.rootComponent, |
|||
baseComponentInfo.fullProps |
|||
) |
|||
} |
|||
@ -1,25 +0,0 @@ |
|||
import { componentsAndScreens } from "./testData" |
|||
import { find } from "lodash/fp" |
|||
import { buildPropsHierarchy } from "../src/userInterface/pagesParsing/buildPropsHierarchy" |
|||
|
|||
describe("buildPropsHierarchy", () => { |
|||
it("should build a complex component children", () => { |
|||
const { components, screens } = componentsAndScreens() |
|||
|
|||
const allprops = buildPropsHierarchy(components, screens, "ButtonGroup") |
|||
|
|||
expect(allprops._component).toEqual("budibase-components/div") |
|||
|
|||
const primaryButtonProps = () => ({ |
|||
_component: "budibase-components/Button", |
|||
}) |
|||
|
|||
const button1 = primaryButtonProps() |
|||
button1.contentText = "Button 1" |
|||
expect(allprops._children[0]).toEqual(button1) |
|||
|
|||
const button2 = primaryButtonProps() |
|||
button2.contentText = "Button 2" |
|||
expect(allprops._children[1]).toEqual(button2) |
|||
}) |
|||
}) |
|||
@ -1,91 +0,0 @@ |
|||
import { |
|||
getInstanceProps, |
|||
getScreenInfo, |
|||
getComponentInfo, |
|||
} from "../src/userInterface/pagesParsing/createProps" |
|||
import { keys, some, find } from "lodash/fp" |
|||
import { componentsAndScreens } from "./testData" |
|||
|
|||
describe("getComponentInfo", () => { |
|||
it("should return default props for root component", () => { |
|||
const result = getComponentInfo( |
|||
componentsAndScreens().components, |
|||
"budibase-components/TextBox" |
|||
) |
|||
|
|||
expect(result.errors).toEqual([]) |
|||
expect(result.fullProps).toEqual({ |
|||
_component: "budibase-components/TextBox", |
|||
size: "", |
|||
isPassword: false, |
|||
placeholder: "", |
|||
label: "", |
|||
}) |
|||
}) |
|||
|
|||
it("getInstanceProps should set supplied props on top of default props", () => { |
|||
const result = getInstanceProps( |
|||
getComponentInfo( |
|||
componentsAndScreens().components, |
|||
"budibase-components/TextBox" |
|||
), |
|||
{ size: "small" } |
|||
) |
|||
|
|||
expect(result).toEqual({ |
|||
_component: "budibase-components/TextBox", |
|||
size: "small", |
|||
isPassword: false, |
|||
placeholder: "", |
|||
label: "", |
|||
}) |
|||
}) |
|||
}) |
|||
|
|||
describe("getScreenInfo", () => { |
|||
const getScreen = (screens, name) => find(s => s.name === name)(screens) |
|||
|
|||
it("should return correct props for screen", () => { |
|||
const { components, screens } = componentsAndScreens() |
|||
const result = getScreenInfo( |
|||
components, |
|||
getScreen(screens, "common/SmallTextbox") |
|||
) |
|||
|
|||
expect(result.errors).toEqual([]) |
|||
expect(result.fullProps).toEqual({ |
|||
_component: "common/SmallTextbox", |
|||
size: "small", |
|||
isPassword: false, |
|||
placeholder: "", |
|||
label: "", |
|||
}) |
|||
}) |
|||
|
|||
it("should return correct props for twice derived component", () => { |
|||
const { components, screens } = componentsAndScreens() |
|||
const result = getScreenInfo( |
|||
components, |
|||
getScreen(screens, "common/PasswordBox") |
|||
) |
|||
|
|||
expect(result.errors).toEqual([]) |
|||
expect(result.fullProps).toEqual({ |
|||
_component: "common/PasswordBox", |
|||
size: "small", |
|||
isPassword: true, |
|||
placeholder: "", |
|||
label: "", |
|||
}) |
|||
}) |
|||
|
|||
it("should list unset props as those that are only defined in root", () => { |
|||
const { components, screens } = componentsAndScreens() |
|||
const result = getScreenInfo( |
|||
components, |
|||
getScreen(screens, "common/PasswordBox") |
|||
) |
|||
|
|||
expect(result.unsetProps).toEqual(["placeholder", "label"]) |
|||
}) |
|||
}) |
|||
@ -0,0 +1,30 @@ |
|||
import { getNewScreen } from "../src/userInterface/pagesParsing/createProps" |
|||
import { componentsAndScreens, stripStandardProps } from "./testData" |
|||
|
|||
describe("geNewScreen", () => { |
|||
it("should return correct props for screen", () => { |
|||
const { components } = componentsAndScreens() |
|||
const result = getNewScreen( |
|||
components, |
|||
"budibase-components/TextBox", |
|||
"newscreen" |
|||
) |
|||
|
|||
expect(result.props._code).toBeDefined() |
|||
expect(result.props._id).toBeDefined() |
|||
expect(result.props._styles).toBeDefined() |
|||
stripStandardProps(result.props) |
|||
|
|||
const expectedProps = { |
|||
_component: "budibase-components/TextBox", |
|||
size: "", |
|||
isPassword: false, |
|||
placeholder: "", |
|||
label: "", |
|||
} |
|||
|
|||
expect(result.props).toEqual(expectedProps) |
|||
expect(result.name).toBe("newscreen") |
|||
expect(result.url).toBeDefined() |
|||
}) |
|||
}) |
|||
@ -0,0 +1,18 @@ |
|||
{ |
|||
"title": "Test App", |
|||
"favicon": "./_shared/favicon.png", |
|||
"stylesheets": [], |
|||
"componentLibraries": ["@budibase/standard-components"], |
|||
"props" : { |
|||
"_component": "@budibase/standard-components/div", |
|||
"_children": [], |
|||
"_id": 0, |
|||
"_styles": { |
|||
"layout": {}, |
|||
"positions": {} |
|||
}, |
|||
"_code": "" |
|||
}, |
|||
"_css": "", |
|||
"uiFunctions": "" |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
{ |
|||
"title": "Test App", |
|||
"favicon": "./_shared/favicon.png", |
|||
"stylesheets": [], |
|||
"componentLibraries": ["@budibase/standard-components"], |
|||
"props" : { |
|||
"_component": "@budibase/standard-components/div", |
|||
"_children": [], |
|||
"_id": 1, |
|||
"_styles": { |
|||
"layout": {}, |
|||
"positions": {} |
|||
}, |
|||
"_code": "" |
|||
}, |
|||
"_css": "", |
|||
"uiFunctions": "" |
|||
} |
|||
@ -0,0 +1 @@ |
|||
whats the craic big lawd ? |
|||
@ -0,0 +1,10 @@ |
|||
import { screenSlotComponent } from "./screenSlotComponent" |
|||
|
|||
export const builtinLibName = "##builtin" |
|||
|
|||
export const isScreenSlot = componentName => |
|||
componentName === "##builtin/screenslot" |
|||
|
|||
export const builtins = window => ({ |
|||
screenslot: screenSlotComponent(window), |
|||
}) |
|||
@ -0,0 +1,73 @@ |
|||
import regexparam from "regexparam" |
|||
import { writable } from "svelte/store" |
|||
|
|||
export const screenRouter = (screens, onScreenSelected) => { |
|||
const routes = screens.map(s => s.route) |
|||
let fallback = routes.findIndex(([p]) => p === "*") |
|||
if (fallback < 0) fallback = 0 |
|||
|
|||
let current |
|||
|
|||
function route(url) { |
|||
const _url = url.state || url |
|||
current = routes.findIndex( |
|||
p => p !== "*" && new RegExp("^" + p + "$").test(_url) |
|||
) |
|||
|
|||
const params = {} |
|||
|
|||
if (current === -1) { |
|||
routes.forEach(([p], i) => { |
|||
const pm = regexparam(p) |
|||
const matches = pm.pattern.exec(_url) |
|||
|
|||
if (!matches) return |
|||
|
|||
let j = 0 |
|||
while (j < pm.keys.length) { |
|||
params[pm.keys[j]] = matches[++j] || null |
|||
} |
|||
|
|||
current = i |
|||
}) |
|||
} |
|||
|
|||
const storeInitial = {} |
|||
storeInitial["##routeParams"] |
|||
const store = writable(storeInitial) |
|||
|
|||
if (current !== -1) { |
|||
onScreenSelected(screens[current], store, _url) |
|||
} else if (fallback) { |
|||
onScreenSelected(screens[fallback], store, _url) |
|||
} |
|||
|
|||
!url.state && history.pushState(_url, null, _url) |
|||
} |
|||
|
|||
function click(e) { |
|||
const x = e.target.closest("a") |
|||
const y = x && x.getAttribute("href") |
|||
|
|||
if ( |
|||
e.ctrlKey || |
|||
e.metaKey || |
|||
e.altKey || |
|||
e.shiftKey || |
|||
e.button || |
|||
e.defaultPrevented |
|||
) |
|||
return |
|||
|
|||
if (!y || x.target || x.host !== location.host) return |
|||
|
|||
e.preventDefault() |
|||
route(y) |
|||
} |
|||
|
|||
addEventListener("popstate", route) |
|||
addEventListener("pushstate", route) |
|||
addEventListener("click", click) |
|||
|
|||
return route |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
export const screenSlotComponent = window => { |
|||
return function(opts) { |
|||
const node = window.document.createElement("DIV") |
|||
const $set = props => { |
|||
props._bb.hydrateChildren(props._children, node) |
|||
} |
|||
const $destroy = () => { |
|||
if (opts.target && node) opts.target.removeChild(node) |
|||
} |
|||
this.$set = $set |
|||
this.$destroy = $destroy |
|||
opts.target.appendChild(node) |
|||
} |
|||
} |
|||
@ -1,66 +1,74 @@ |
|||
import { load } from "./testAppDef" |
|||
import { load, makePage } from "./testAppDef" |
|||
|
|||
describe("controlFlow", () => { |
|||
it("should display simple div, with always true render function", async () => { |
|||
const { dom } = await load({ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "always_render", |
|||
}) |
|||
const { dom } = await load( |
|||
makePage({ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "always_render", |
|||
}) |
|||
) |
|||
|
|||
expect(dom.window.document.body.children.length).toBe(1) |
|||
const child = dom.window.document.body.children[0] |
|||
expect(child.className).toBe("my-test-class") |
|||
expect(child.className.includes("my-test-class")).toBeTruthy() |
|||
}) |
|||
|
|||
it("should not display div, with always false render function", async () => { |
|||
const { dom } = await load({ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "never_render", |
|||
}) |
|||
const { dom } = await load( |
|||
makePage({ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "never_render", |
|||
}) |
|||
) |
|||
|
|||
expect(dom.window.document.body.children.length).toBe(0) |
|||
}) |
|||
|
|||
it("should display 3 divs in a looped render function", async () => { |
|||
const { dom } = await load({ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "three_clones", |
|||
}) |
|||
const { dom } = await load( |
|||
makePage({ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "three_clones", |
|||
}) |
|||
) |
|||
|
|||
expect(dom.window.document.body.children.length).toBe(3) |
|||
|
|||
const child0 = dom.window.document.body.children[0] |
|||
expect(child0.className).toBe("my-test-class") |
|||
expect(child0.className.includes("my-test-class")).toBeTruthy() |
|||
|
|||
const child1 = dom.window.document.body.children[1] |
|||
expect(child1.className).toBe("my-test-class") |
|||
expect(child1.className.includes("my-test-class")).toBeTruthy() |
|||
|
|||
const child2 = dom.window.document.body.children[2] |
|||
expect(child2.className).toBe("my-test-class") |
|||
expect(child2.className.includes("my-test-class")).toBeTruthy() |
|||
}) |
|||
|
|||
it("should display 3 div, in a looped render, as children", async () => { |
|||
const { dom } = await load({ |
|||
_component: "testlib/div", |
|||
_children: [ |
|||
{ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "three_clones", |
|||
}, |
|||
], |
|||
}) |
|||
const { dom } = await load( |
|||
makePage({ |
|||
_component: "testlib/div", |
|||
_children: [ |
|||
{ |
|||
_component: "testlib/div", |
|||
className: "my-test-class", |
|||
_id: "three_clones", |
|||
}, |
|||
], |
|||
}) |
|||
) |
|||
|
|||
expect(dom.window.document.body.children.length).toBe(1) |
|||
|
|||
const rootDiv = dom.window.document.body.children[0] |
|||
expect(rootDiv.children.length).toBe(3) |
|||
|
|||
expect(rootDiv.children[0].className).toBe("my-test-class") |
|||
expect(rootDiv.children[1].className).toBe("my-test-class") |
|||
expect(rootDiv.children[2].className).toBe("my-test-class") |
|||
expect(rootDiv.children[0].className.includes("my-test-class")).toBeTruthy() |
|||
expect(rootDiv.children[1].className.includes("my-test-class")).toBeTruthy() |
|||
expect(rootDiv.children[2].className.includes("my-test-class")).toBeTruthy() |
|||
}) |
|||
}) |
|||
|
|||
@ -0,0 +1,137 @@ |
|||
import { load, makePage, makeScreen, walkComponentTree } from "./testAppDef" |
|||
import { isScreenSlot } from "../src/render/builtinComponents" |
|||
|
|||
describe("screenRouting", () => { |
|||
it("should load correct screen, for initial URL", async () => { |
|||
const { page, screens } = pageWith3Screens() |
|||
const { dom } = await load(page, screens, "/screen2") |
|||
|
|||
const rootDiv = dom.window.document.body.children[0] |
|||
expect(rootDiv.children.length).toBe(1) |
|||
|
|||
const screenRoot = rootDiv.children[0] |
|||
|
|||
expect(screenRoot.children.length).toBe(1) |
|||
expect(screenRoot.children[0].children.length).toBe(1) |
|||
expect(screenRoot.children[0].children[0].innerText).toBe("screen 2") |
|||
}) |
|||
|
|||
it("should be able to route to the correct screen", async () => { |
|||
const { page, screens } = pageWith3Screens() |
|||
const { dom, app } = await load(page, screens, "/screen2") |
|||
|
|||
app.routeTo()("/screen3") |
|||
const rootDiv = dom.window.document.body.children[0] |
|||
expect(rootDiv.children.length).toBe(1) |
|||
|
|||
const screenRoot = rootDiv.children[0] |
|||
|
|||
expect(screenRoot.children.length).toBe(1) |
|||
expect(screenRoot.children[0].children.length).toBe(1) |
|||
expect(screenRoot.children[0].children[0].innerText).toBe("screen 3") |
|||
}) |
|||
|
|||
it("should destroy and unsubscribe all components on a screen whe screen is changed", async () => { |
|||
const { page, screens } = pageWith3Screens() |
|||
const { app } = await load(page, screens, "/screen2") |
|||
|
|||
const nodes = createTrackerNodes(app) |
|||
|
|||
app.routeTo()("/screen3") |
|||
|
|||
expect(nodes.length > 0).toBe(true) |
|||
expect( |
|||
nodes.some(n => n.isDestroyed === false && isUnderScreenSlot(n.node)) |
|||
).toBe(false) |
|||
expect( |
|||
nodes.some(n => n.isUnsubscribed === false && isUnderScreenSlot(n.node)) |
|||
).toBe(false) |
|||
}) |
|||
|
|||
it("should not destroy and unsubscribe page and screenslot components when screen is changed", async () => { |
|||
const { page, screens } = pageWith3Screens() |
|||
const { app } = await load(page, screens, "/screen2") |
|||
|
|||
const nodes = createTrackerNodes(app) |
|||
|
|||
app.routeTo()("/screen3") |
|||
|
|||
expect(nodes.length > 0).toBe(true) |
|||
expect( |
|||
nodes.some(n => n.isDestroyed === true && !isUnderScreenSlot(n.node)) |
|||
).toBe(false) |
|||
}) |
|||
}) |
|||
|
|||
const createTrackerNodes = app => { |
|||
const nodes = [] |
|||
walkComponentTree(app.rootNode(), n => { |
|||
if (!n.component) return |
|||
const tracker = { node: n, isDestroyed: false, isUnsubscribed: false } |
|||
const _destroy = n.component.$destroy |
|||
n.component.$destroy = () => { |
|||
_destroy() |
|||
tracker.isDestroyed = true |
|||
} |
|||
const _unsubscribe = n.unsubscribe |
|||
if (!_unsubscribe) { |
|||
tracker.isUnsubscribed = undefined |
|||
} else { |
|||
n.unsubscribe = () => { |
|||
_unsubscribe() |
|||
tracker.isUnsubscribed = true |
|||
} |
|||
} |
|||
nodes.push(tracker) |
|||
}) |
|||
return nodes |
|||
} |
|||
|
|||
const isUnderScreenSlot = node => |
|||
node.parentNode && |
|||
(isScreenSlot(node.parentNode.props._component) || |
|||
isUnderScreenSlot(node.parentNode)) |
|||
|
|||
const pageWith3Screens = () => ({ |
|||
page: makePage({ |
|||
_component: "testlib/div", |
|||
_children: [ |
|||
{ |
|||
_component: "##builtin/screenslot", |
|||
text: "header one", |
|||
}, |
|||
], |
|||
}), |
|||
screens: [ |
|||
makeScreen("/", { |
|||
_component: "testlib/div", |
|||
className: "screen-class", |
|||
_children: [ |
|||
{ |
|||
_component: "testlib/h1", |
|||
text: "screen 1", |
|||
}, |
|||
], |
|||
}), |
|||
makeScreen("/screen2", { |
|||
_component: "testlib/div", |
|||
className: "screen-class", |
|||
_children: [ |
|||
{ |
|||
_component: "testlib/h1", |
|||
text: "screen 2", |
|||
}, |
|||
], |
|||
}), |
|||
makeScreen("/screen3", { |
|||
_component: "testlib/div", |
|||
className: "screen-class", |
|||
_children: [ |
|||
{ |
|||
_component: "testlib/h1", |
|||
text: "screen 3", |
|||
}, |
|||
], |
|||
}), |
|||
], |
|||
}) |
|||
@ -1,2 +1,2 @@ |
|||
import "./_index.scss"; |
|||
export { default as button } from "./Button.svelte"; |
|||
import "./_index.scss" |
|||
export { default as button } from "./Button.svelte" |
|||
|
|||
@ -1,70 +1,38 @@ |
|||
export default class ClassBuilder { |
|||
constructor(block, defaultIgnoreList) { |
|||
this.block = `mdc-${block}`; |
|||
this.defaultIgnoreList = defaultIgnoreList; //will be ignored when building custom classes
|
|||
constructor(block, customDefaults) { |
|||
this.block = `mdc-${block}` |
|||
this.customDefaults = customDefaults //will be ignored when building custom classes
|
|||
} |
|||
|
|||
/* |
|||
handles both blocks and elementss (BEM MD Notation) |
|||
params = {elementName: string, props: {modifiers{}, customs:{}, extras: []}} |
|||
All are optional |
|||
*/ |
|||
build(params) { |
|||
if (!params) return this.block; //return block if nothing passed
|
|||
const { props, elementName } = params; |
|||
let base = !!elementName ? `${this.block}__${elementName}` : this.block; |
|||
if (!props) return base; |
|||
return this._handleProps(base, props); |
|||
// classParams: {modifiers:[] (mdc), custom:[] (bbmd), extra:[] (any)}
|
|||
blocks(classParams) { |
|||
let base = this.block |
|||
if (classParams == undefined) return base |
|||
return this.buildClass(base, classParams) |
|||
} |
|||
|
|||
//Easily grab a simple element class
|
|||
elem(elementName) { |
|||
return this.build({ elementName }); |
|||
//elementName: string, classParams: {}
|
|||
elements(elementName, classParams) { |
|||
let base = `${this.block}__${elementName}` |
|||
if (classParams == undefined) return base |
|||
return this.buildClass(base, classParams) |
|||
} |
|||
|
|||
//use if a different base is needed than whats defined by this.block
|
|||
debase(base, elementProps) { |
|||
if (!elementProps) return base; |
|||
return this._handleProps(base, elementProps); |
|||
} |
|||
|
|||
//proxies bindProps and checks for which elementProps exist before binding
|
|||
_handleProps(base, elementProps) { |
|||
let cls = base; |
|||
const { modifiers, customs, extras } = elementProps; |
|||
if (!!modifiers) cls += this._bindProps(modifiers, base); |
|||
if (!!customs) cls += this._bindProps(customs, base, true); |
|||
if (!!extras) cls += ` ${extras.join(" ")}`; |
|||
return cls.trim(); |
|||
} |
|||
|
|||
/* |
|||
Handles both modifiers and customs. Use property, value or both depending |
|||
on whether it is passsed props for custom or modifiers |
|||
if custom uses the following convention for scss mixins: |
|||
bbmd-{this.block}--{property}-{value} |
|||
bbmd-mdc-button--size-large |
|||
*/ |
|||
_bindProps(elementProps, base, isCustom = false) { |
|||
return Object.entries(elementProps) |
|||
.map(([property, value]) => { |
|||
//disregard falsy and values set by defaultIgnoreList constructor param
|
|||
if ( |
|||
!!value && |
|||
(!this.defaultIgnoreList || !this.defaultIgnoreList.includes(value)) |
|||
) { |
|||
let classBase = isCustom ? `bbmd-${base}` : `${base}`; |
|||
let valueType = typeof value; |
|||
|
|||
if (valueType == "string" || valueType == "number") { |
|||
return isCustom |
|||
? ` ${classBase}--${property}-${value}` |
|||
: ` ${classBase}--${value}`; |
|||
} else if (valueType == "boolean") { |
|||
return ` ${classBase}--${property}`; |
|||
buildClass(base, classParams) { |
|||
let cls = base |
|||
const { modifiers, customs, extras } = classParams |
|||
if (modifiers) cls += modifiers.map(m => ` ${base}--${m}`).join(" ") |
|||
if (customs) |
|||
cls += Object.entries(customs) |
|||
.map(([property, value]) => { |
|||
//disregard falsy and values set by customDefaults constructor param
|
|||
if (!!value && !this.customDefaults.includes(value)) { |
|||
//custom scss name convention = bbmd-[block | element]--[property]-[value]
|
|||
return ` bbmd-${base}--${property}-${value}` |
|||
} |
|||
} |
|||
}) |
|||
.join(""); |
|||
}) |
|||
.join("") |
|||
if (extras) cls += ` ${extras.join(" ")}` |
|||
return cls.trim() |
|||
} |
|||
} |
|||
|
|||
@ -1,28 +1,28 @@ |
|||
import { MDCRipple } from "@material/ripple"; |
|||
import { MDCRipple } from "@material/ripple" |
|||
|
|||
export default function ripple( |
|||
node, |
|||
props = { colour: "primary", unbounded: false } |
|||
) { |
|||
node.classList.add("mdc-ripple-surface"); |
|||
const component = new MDCRipple(node); |
|||
component.unbounded = props.unbounded; |
|||
node.classList.add("mdc-ripple-surface") |
|||
const component = new MDCRipple(node) |
|||
component.unbounded = props.unbounded |
|||
|
|||
if (props.colour === "secondary") { |
|||
node.classList.remove("mdc-ripple-surface--primary"); |
|||
node.classList.add("mdc-ripple-surface--accent"); |
|||
node.classList.remove("mdc-ripple-surface--primary") |
|||
node.classList.add("mdc-ripple-surface--accent") |
|||
} else { |
|||
node.classList.add("mdc-ripple-surface--primary"); |
|||
node.classList.remove("mdc-ripple-surface--accent"); |
|||
node.classList.add("mdc-ripple-surface--primary") |
|||
node.classList.remove("mdc-ripple-surface--accent") |
|||
} |
|||
|
|||
return { |
|||
destroy() { |
|||
component.destroy(); |
|||
node.classList.remove("mdc-ripple-surface"); |
|||
node.classList.remove("mdc-ripple-surface--primary"); |
|||
node.classList.remove("mdc-ripple-surface--accent"); |
|||
component = null; |
|||
} |
|||
}; |
|||
component.destroy() |
|||
node.classList.remove("mdc-ripple-surface") |
|||
node.classList.remove("mdc-ripple-surface--primary") |
|||
node.classList.remove("mdc-ripple-surface--accent") |
|||
component = null |
|||
}, |
|||
} |
|||
} |
|||
|
|||
@ -1,3 +1,4 @@ |
|||
import { button, icon, textfield, H1, Overline } from "@BBMD"; |
|||
export default { H1, Overline, button, icon, textfield }; |
|||
import h1 from "../H1.svelte" |
|||
import { button, icon } from "@BBMD" |
|||
|
|||
export default { h1, button, icon } |
|||
|
|||
@ -1,6 +1,3 @@ |
|||
// export { default as h1 } from "./H1.svelte";
|
|||
|
|||
export { default as icon } from "./Icon.svelte"; |
|||
export { button } from "./Button"; |
|||
export { textfield } from "./Textfield"; |
|||
export * from "./Typography" |
|||
export { default as h1 } from "./H1.svelte" |
|||
export { default as icon } from "./Icon.svelte" |
|||
export { button } from "./Button" |
|||
|
|||
@ -1,8 +1,4 @@ |
|||
myapps/ |
|||
config.js |
|||
<<<<<<< HEAD |
|||
/builder/* |
|||
!/builder/assets/ |
|||
======= |
|||
builder/ |
|||
>>>>>>> ee5a4e8c962b29242152cbbd8065d8f3ccf65eaf |
|||
!/builder/assets/ |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -1,25 +0,0 @@ |
|||
{ |
|||
"main": { |
|||
"index": {}, |
|||
"appBody": "./main.app.json" |
|||
}, |
|||
"unauthenticated": { |
|||
"index": { |
|||
"_component": "budibase-components/indexHtml", |
|||
"title": "Test App 1 - Login", |
|||
"customScripts": [ |
|||
"MyCustomComponents.js" |
|||
] |
|||
}, |
|||
"appBody": "./unauthenticated.app.json" |
|||
}, |
|||
"componentLibraries": [ |
|||
"./customComponents", |
|||
"./moreCustomComponents", |
|||
"@budibase/standard-components" |
|||
], |
|||
"stylesheets": [ |
|||
"https://css-r-us.com/myawesomestyles.css", |
|||
"/local.css" |
|||
] |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
{ |
|||
"title": "Test App", |
|||
"favicon": "./_shared/favicon.png", |
|||
"stylesheets": [ |
|||
"my-styles.css" |
|||
], |
|||
"componentLibraries": [ |
|||
"./customComponents", |
|||
"./moreCustomComponents" |
|||
], |
|||
"props": { |
|||
"_component": "@budibase/standard-components/div" |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
{ |
|||
"name": "screen1", |
|||
"description": "", |
|||
"props": { |
|||
"_component": "@budibase/standard-components/div", |
|||
"className": "" |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
{ |
|||
"name": "screen2", |
|||
"description": "", |
|||
"props": { |
|||
"_component": "@budibase/standard-components/div", |
|||
"className": "" |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"title": "Test App", |
|||
"favicon": "./_shared/favicon.png", |
|||
"stylesheets": ["my-styles.css"], |
|||
"componentLibraries": ["./customComponents","./moreCustomComponents"], |
|||
"props" : { |
|||
"_component": "@budibase/standard-components/div" |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -1,79 +1,2 @@ |
|||
window["##BUDIBASE_APPDEFINITION##"] = { |
|||
hierarchy: { |
|||
name: "root", |
|||
type: "root", |
|||
children: [ |
|||
{ |
|||
name: "customer", |
|||
type: "record", |
|||
fields: [ |
|||
{ |
|||
name: "name", |
|||
type: "string", |
|||
typeOptions: { |
|||
maxLength: 1000, |
|||
values: null, |
|||
allowDeclaredValuesOnly: false, |
|||
}, |
|||
label: "name", |
|||
getInitialValue: "default", |
|||
getUndefinedValue: "default", |
|||
}, |
|||
], |
|||
children: [ |
|||
{ |
|||
name: "invoiceyooo", |
|||
type: "record", |
|||
fields: [ |
|||
{ |
|||
name: "amount", |
|||
type: "number", |
|||
typeOptions: { |
|||
minValue: 99999999999, |
|||
maxValue: 99999999999, |
|||
decimalPlaces: 2, |
|||
}, |
|||
label: "amount", |
|||
getInitialValue: "default", |
|||
getUndefinedValue: "default", |
|||
}, |
|||
], |
|||
children: [], |
|||
validationRules: [], |
|||
nodeId: 2, |
|||
indexes: [], |
|||
allidsShardFactor: 1, |
|||
collectionName: "invoices", |
|||
isSingle: false, |
|||
}, |
|||
], |
|||
validationRules: [], |
|||
nodeId: 1, |
|||
indexes: [], |
|||
allidsShardFactor: 64, |
|||
collectionName: "customers", |
|||
isSingle: false, |
|||
}, |
|||
], |
|||
pathMaps: [], |
|||
indexes: [], |
|||
nodeId: 0, |
|||
}, |
|||
componentLibraries: [ |
|||
{ |
|||
importPath: "/lib/customComponents/index.js", |
|||
libName: "./customComponents", |
|||
}, |
|||
{ |
|||
importPath: "/lib/moreCustomComponents/index.js", |
|||
libName: "./moreCustomComponents", |
|||
}, |
|||
{ |
|||
importPath: |
|||
"/lib/node_modules/@budibase/standard-components/dist/index.js", |
|||
libName: "@budibase/standard-components", |
|||
}, |
|||
], |
|||
appRootPath: "", |
|||
props: { _component: "some_component" }, |
|||
} |
|||
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[],"nodeId":0},"componentLibraries":[{"importPath":"/lib/customComponents/index.js","libName":"./customComponents"},{"importPath":"/lib/moreCustomComponents/index.js","libName":"./moreCustomComponents"}],"appRootPath":"","page":{"title":"Test App","favicon":"./_shared/favicon.png","stylesheets":["my-styles.css"],"componentLibraries":["./customComponents","./moreCustomComponents"],"props":{"_component":"@budibase/standard-components/div"}},"screens":[{"name":"screen1","description":"","props":{"_component":"@budibase/standard-components/div","className":""},"_css":"/css/d121e1ecc6cf44f433213222e9ff5d40.css"},{"name":"screen2","description":"","props":{"_component":"@budibase/standard-components/div","className":""},"_css":"/css/7b7c05b78e05c06eb8d69475caadfea3.css"}]}; |
|||
window['##BUDIBASE_UIFUNCTIONS##'] = {'1234':() => 'test return'} |
|||
@ -0,0 +1 @@ |
|||
/*screen2 css*/ |
|||
@ -0,0 +1 @@ |
|||
/*screen1 css*/ |
|||
@ -0,0 +1 @@ |
|||
/*main page css*/ |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,43 @@ |
|||
const crypto = require("crypto") |
|||
const { ensureDir, emptyDir, writeFile } = require("fs-extra") |
|||
const { join } = require("path") |
|||
|
|||
module.exports.convertCssToFiles = async (publicPagePath, pkg) => { |
|||
const cssDir = join(publicPagePath, "css") |
|||
await ensureDir(cssDir) |
|||
await emptyDir(cssDir) |
|||
|
|||
for (let screen of pkg.screens) { |
|||
if (!screen._css) continue |
|||
if (screen._css.trim().length === 0) { |
|||
delete screen._css |
|||
continue |
|||
} |
|||
screen._css = await createCssFile(cssDir, screen._css) |
|||
} |
|||
|
|||
if (pkg.page._css) { |
|||
pkg.page._css = await createCssFile(cssDir, pkg.page._css) |
|||
} |
|||
} |
|||
|
|||
module.exports.getHashedCssPaths = (cssDir, _css) => { |
|||
const fileName = |
|||
crypto |
|||
.createHash("md5") |
|||
.update(_css) |
|||
.digest("hex") + ".css" |
|||
|
|||
const filePath = join(cssDir, fileName) |
|||
const url = `/css/${fileName}` |
|||
|
|||
return { filePath, url } |
|||
} |
|||
|
|||
const createCssFile = async (cssDir, _css) => { |
|||
const { filePath, url } = module.exports.getHashedCssPaths(cssDir, _css) |
|||
|
|||
await writeFile(filePath, _css) |
|||
|
|||
return url |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
const { appPackageFolder } = require("../createAppPackage") |
|||
const { writeJSON } = require("fs-extra") |
|||
const buildApp = require("./buildApp") |
|||
|
|||
module.exports = async (config, appname, pkg) => { |
|||
const appPath = appPackageFolder(config, appname) |
|||
await writeJSON(`${appPath}/appDefinition.json`, pkg.appDefinition, { |
|||
spaces: 2, |
|||
}) |
|||
|
|||
await writeJSON(`${appPath}/access_levels.json`, pkg.accessLevels, { |
|||
spaces: 2, |
|||
}) |
|||
|
|||
await writeJSON(`${appPath}/pages.json`, pkg.pages, { spaces: 2 }) |
|||
|
|||
await buildApp(config, appname, pkg.pages, pkg.appDefinition) |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
const { appPackageFolder } = require("../createAppPackage") |
|||
const { writeJSON } = require("fs-extra") |
|||
const { join } = require("path") |
|||
|
|||
const buildPage = require("./buildPage") |
|||
|
|||
module.exports = async (config, appname, pageName, pkg) => { |
|||
const appPath = appPackageFolder(config, appname) |
|||
pkg.pageName = pageName |
|||
|
|||
await writeJSON(`${appPath}/appDefinition.json`, pkg.appDefinition, { |
|||
spaces: 2, |
|||
}) |
|||
|
|||
await writeJSON(`${appPath}/access_levels.json`, pkg.accessLevels, { |
|||
spaces: 2, |
|||
}) |
|||
|
|||
await buildPage(config, appname, pkg) |
|||
|
|||
const pageFile = join(appPath, "pages", pageName, "page.json") |
|||
|
|||
if (pkg.page._css) { |
|||
delete pkg.page._css |
|||
} |
|||
|
|||
await writeJSON(pageFile, pkg.page, { |
|||
spaces: 2, |
|||
}) |
|||
} |
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue