Creating CSS generation capabilities in the server.
This commit is contained in:
parent
b1bb7abdef
commit
5eec4d7a47
|
@ -30,6 +30,7 @@ const { BASE_LAYOUTS } = require("../../constants/layouts")
|
|||
const { HOME_SCREEN } = require("../../constants/screens")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { recurseMustache } = require("../../utilities/mustache")
|
||||
const { generateAssetCss } = require("../../utilities/builder/generateCss")
|
||||
|
||||
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
||||
|
||||
|
@ -119,9 +120,14 @@ exports.fetchAppDefinition = async function(ctx) {
|
|||
exports.fetchAppPackage = async function(ctx) {
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const application = await db.get(ctx.params.appId)
|
||||
const layouts = await getLayouts(db)
|
||||
const screens = await getScreens(db)
|
||||
const [layouts, screens] = await Promise.all([getLayouts(db), getScreens(db)])
|
||||
|
||||
for (let layout of layouts) {
|
||||
layout._css = generateAssetCss([layout.props])
|
||||
}
|
||||
for (let screen of screens) {
|
||||
screen._css = generateAssetCss([screen.props])
|
||||
}
|
||||
ctx.body = {
|
||||
application,
|
||||
screens,
|
||||
|
|
|
@ -17,10 +17,16 @@ const setBuilderToken = require("../../../utilities/builder/setBuilderToken")
|
|||
const fileProcessor = require("../../../utilities/fileProcessor")
|
||||
const { AuthTypes } = require("../../../constants")
|
||||
const env = require("../../../environment")
|
||||
const { generateAssetCss } = require("../../../utilities/builder/generateCss")
|
||||
|
||||
// this was the version before we started versioning the component library
|
||||
const COMP_LIB_BASE_APP_VERSION = "0.2.5"
|
||||
|
||||
exports.generateCss = async function(ctx) {
|
||||
const structure = ctx.request.body
|
||||
ctx.body = generateAssetCss(structure)
|
||||
}
|
||||
|
||||
exports.serveBuilder = async function(ctx) {
|
||||
let builderPath = resolve(__dirname, "../../../../builder")
|
||||
if (ctx.file === "index.html") {
|
||||
|
|
|
@ -24,6 +24,7 @@ if (env.NODE_ENV !== "production") {
|
|||
}
|
||||
|
||||
router
|
||||
.post("/api/css/generate", authorized(BUILDER), controller.generateCss)
|
||||
.post(
|
||||
"/api/attachments/process",
|
||||
authorized(BUILDER),
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
const { generateAssetCss, generateCss } = require("../../../utilities/builder/generateCss")
|
||||
|
||||
describe("generate_css", () => {
|
||||
it("Check how array styles are output", () => {
|
||||
expect(generateCss({ margin: ["0", "10", "0", "15"] })).toBe("margin: 0 10 0 15;")
|
||||
})
|
||||
|
||||
it("Check handling of an array with empty string values", () => {
|
||||
expect(generateCss({ padding: ["", "", "", ""] })).toBe("")
|
||||
})
|
||||
|
||||
it("Check handling of an empty array", () => {
|
||||
expect(generateCss({ margin: [] })).toBe("")
|
||||
})
|
||||
|
||||
it("Check handling of valid font property", () => {
|
||||
expect(generateCss({ "font-size": "10px" })).toBe("font-size: 10px;")
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe("generate_screen_css", () => {
|
||||
const normalComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: { "font-size": "16px" }, hover: {}, active: {}, selected: {} } }
|
||||
|
||||
it("Test generation of normal css styles", () => {
|
||||
expect(generateAssetCss([normalComponent])).toBe(".header-123-456 {\nfont-size: 16px;\n}")
|
||||
})
|
||||
|
||||
const hoverComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: {}, hover: {"font-size": "16px"}, active: {}, selected: {} } }
|
||||
|
||||
it("Test generation of hover css styles", () => {
|
||||
expect(generateAssetCss([hoverComponent])).toBe(".header-123-456:hover {\nfont-size: 16px;\n}")
|
||||
})
|
||||
|
||||
const selectedComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: {}, hover: {}, active: {}, selected: { "font-size": "16px" } } }
|
||||
|
||||
it("Test generation of selection css styles", () => {
|
||||
expect(generateAssetCss([selectedComponent])).toBe(".header-123-456::selection {\nfont-size: 16px;\n}")
|
||||
})
|
||||
|
||||
const emptyComponent = { _id: "123-456", _component: "@standard-components/header", _children: [], _styles: { normal: {}, hover: {}, active: {}, selected: {} } }
|
||||
|
||||
it("Testing handling of empty component styles", () => {
|
||||
expect(generateAssetCss([emptyComponent])).toBe("")
|
||||
})
|
||||
})
|
|
@ -104,5 +104,31 @@ exports.HOME_SCREEN = {
|
|||
route: "/",
|
||||
accessLevelId: BUILTIN_LEVEL_IDS.BASIC,
|
||||
},
|
||||
name: "d834fea2-1b3e-4320-ab34-f9009f5ecc59",
|
||||
name: "home-screen",
|
||||
}
|
||||
|
||||
exports.LOGIN_SCREEN = {
|
||||
description: "",
|
||||
url: "",
|
||||
props: {
|
||||
_id: "781e497e-2e7c-11eb-adc1-0242ac120002",
|
||||
_component: "@budibase/standard-components/login",
|
||||
_styles: {
|
||||
normal: {},
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
_code: "",
|
||||
className: "",
|
||||
onLoad: [],
|
||||
type: "div",
|
||||
_children: [],
|
||||
_instanceName: "Login",
|
||||
},
|
||||
routing: {
|
||||
route: "/",
|
||||
accessLevelId: BUILTIN_LEVEL_IDS.PUBLIC,
|
||||
},
|
||||
name: "login-screen",
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
exports.generateAssetCss = 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 = exports.generateCss(_styles[selector])
|
||||
if (cssString) {
|
||||
styles += exports.applyClass(_id, componentName, cssString, selector)
|
||||
}
|
||||
})
|
||||
if (_children && _children.length) {
|
||||
styles += exports.generateAssetCss(_children) + "\n"
|
||||
}
|
||||
}
|
||||
return styles.trim()
|
||||
}
|
||||
|
||||
exports.generateCss = style => {
|
||||
let cssString = Object.entries(style).reduce((str, [key, value]) => {
|
||||
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.join(" ")};\n`)
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}, "")
|
||||
|
||||
return (cssString || "").trim()
|
||||
}
|
||||
|
||||
exports.applyClass = (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}`
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue