Merge branch 'master' of https://github.com/Budibase/budibase into property-panel/screen-page-testing

This commit is contained in:
Conor_Mack 2020-06-10 10:19:58 +01:00
commit 7eca5a501d
11 changed files with 151 additions and 322 deletions

View File

@ -39,7 +39,7 @@
}, },
"dependencies": { "dependencies": {
"@beyonk/svelte-notifications": "^2.0.3", "@beyonk/svelte-notifications": "^2.0.3",
"@budibase/bbui": "^0.3.5", "@budibase/bbui": "^1.1.1",
"@budibase/client": "^0.0.32", "@budibase/client": "^0.0.32",
"@nx-js/compiler-util": "^2.0.0", "@nx-js/compiler-util": "^2.0.0",
"codemirror": "^5.51.0", "codemirror": "^5.51.0",

View File

@ -69,7 +69,6 @@ export const getStore = () => {
store.getPathToComponent = getPathToComponent(store) store.getPathToComponent = getPathToComponent(store)
store.addTemplatedComponent = addTemplatedComponent(store) store.addTemplatedComponent = addTemplatedComponent(store)
store.setMetadataProp = setMetadataProp(store) store.setMetadataProp = setMetadataProp(store)
store.editPageOrScreen = editPageOrScreen(store)
return store return store
} }
@ -172,15 +171,6 @@ const createScreen = store => (screenName, route, layoutComponentName) => {
}) })
} }
const editPageOrScreen = store => (key, value) => {
store.update(state => {
state.currentPreviewItem[key] = value
_saveCurrentPreviewItem(state)
return state
})
}
const setCurrentScreen = store => screenName => { const setCurrentScreen = store => screenName => {
store.update(s => { store.update(s => {
const screen = getExactComponent(s.screens, screenName) const screen = getExactComponent(s.screens, screenName)
@ -295,7 +285,6 @@ const setCurrentPage = store => pageName => {
state.currentFrontEndType = "page" state.currentFrontEndType = "page"
state.currentPageName = pageName state.currentPageName = pageName
state.currentView = "detail"
state.screens = Array.isArray(current_screens) state.screens = Array.isArray(current_screens)
? current_screens ? current_screens
: Object.values(current_screens) : Object.values(current_screens)
@ -456,7 +445,6 @@ const setScreenType = store => type => {
state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null
state.currentPreviewItem = pageOrScreen state.currentPreviewItem = pageOrScreen
state.currentView = "detail"
return state return state
}) })
} }

View File

@ -10,18 +10,18 @@
export let onChange = () => {} export let onChange = () => {}
function handleChange(val, idx) { function handleChange(val, idx) {
value.splice(idx, 1, val !== "auto" ? val + suffix : val) value.splice(idx, 1, val !== "auto" && suffix ? val + suffix : val)
value = value value = value
let _value = value.map(v => let _value = value.map(v =>
!v.endsWith(suffix) && v !== "auto" ? v + suffix : v suffix && !v.endsWith(suffix) && v !== "auto" ? v + suffix : v
) )
onChange(_value) onChange(_value)
} }
$: displayValues = value $: displayValues = value && suffix
? value.map(v => v.replace(new RegExp(`${suffix}$`), "")) ? value.map(v => v.replace(new RegExp(`${suffix}$`), ""))
: [] : value || []
</script> </script>
<div class="input-container"> <div class="input-container">

View File

@ -21,42 +21,7 @@
return componentName || "element" return componentName || "element"
} }
$: iframe && const screenPlaceholder = {
console.log(
iframe.contentDocument.head.insertAdjacentHTML(
"beforeend",
`<\style></style>`
)
)
$: hasComponent = !!$store.currentPreviewItem
$: {
styles = ""
// Apply the CSS from the currently selected page and its screens
const currentPage = $store.pages[$store.currentPageName]
styles += currentPage._css
for (let screen of currentPage._screens) {
styles += screen._css
}
styles = styles
}
$: stylesheetLinks = pipe($store.pages.stylesheets, [
map(s => `<link rel="stylesheet" href="${s}"/>`),
join("\n"),
])
$: screensExist =
$store.currentPreviewItem._screens &&
$store.currentPreviewItem._screens.length > 0
$: frontendDefinition = {
appId: $store.appId,
libraries: $store.libraries,
page: $store.currentPreviewItem,
screens: screensExist
? $store.currentPreviewItem._screens
: [
{
name: "Screen Placeholder", name: "Screen Placeholder",
route: "*", route: "*",
props: { props: {
@ -93,7 +58,39 @@
}, },
], ],
}, },
}, }
$: hasComponent = !!$store.currentPreviewItem
$: {
styles = ""
// Apply the CSS from the currently selected page and its screens
const currentPage = $store.pages[$store.currentPageName]
styles += currentPage._css
for (let screen of currentPage._screens) {
styles += screen._css
}
styles = styles
}
$: stylesheetLinks = pipe($store.pages.stylesheets, [
map(s => `<link rel="stylesheet" href="${s}"/>`),
join("\n"),
])
$: screensExist =
$store.currentPreviewItem._screens &&
$store.currentPreviewItem._screens.length > 0
$: frontendDefinition = {
appId: $store.appId,
libraries: $store.libraries,
page: $store.pages[$store.currentPageName],
screens: [
$store.currentFrontEndType === "page"
? screenPlaceholder
: $store.currentPreviewItem,
], ],
appRootPath: "", appRootPath: "",
} }
@ -103,6 +100,22 @@
$: selectedComponentId = $store.currentComponentInfo $: selectedComponentId = $store.currentComponentInfo
? $store.currentComponentInfo._id ? $store.currentComponentInfo._id
: "" : ""
const refreshContent = () => {
iframe.contentWindow.postMessage(JSON.stringify({
styles,
stylesheetLinks,
selectedComponentType,
selectedComponentId,
frontendDefinition,
}))
}
$: if(iframe) iframe.contentWindow.addEventListener("bb-ready", refreshContent, { once: true })
$: if(iframe && frontendDefinition) {
refreshContent()
}
</script> </script>
<div class="component-container"> <div class="component-container">
@ -111,13 +124,7 @@
style="height: 100%; width: 100%" style="height: 100%; width: 100%"
title="componentPreview" title="componentPreview"
bind:this={iframe} bind:this={iframe}
srcdoc={iframeTemplate({ srcdoc={iframeTemplate} />
styles,
stylesheetLinks,
selectedComponentType,
selectedComponentId,
frontendDefinition: JSON.stringify(frontendDefinition),
})} />
{/if} {/if}
</div> </div>

View File

@ -1,20 +1,6 @@
export default ({ export default `<html>
styles,
stylesheetLinks,
selectedComponentType,
selectedComponentId,
frontendDefinition,
}) => `<html>
<head> <head>
${stylesheetLinks}
<style> <style>
${styles || ""}
.${selectedComponentType}-${selectedComponentId} {
border: 2px solid #0055ff;
}
body, html { body, html {
height: 100%!important; height: 100%!important;
font-family: Roboto !important; font-family: Roboto !important;
@ -35,11 +21,49 @@ export default ({
} }
</style> </style>
<script> <script>
window["##BUDIBASE_FRONTEND_DEFINITION##"] = ${frontendDefinition}; function receiveMessage(event) {
if (!event.data) return
const data = JSON.parse(event.data)
try {
if (styles) document.head.removeChild(styles)
} catch(_) { }
try {
if (selectedComponentStyle) document.head.removeChild(selectedComponentStyle)
} catch(_) { }
selectedComponentStyle = document.createElement('style');
document.head.appendChild(selectedComponentStyle)
var selectedCss = '.' + data.selectedComponentType + '-' + data.selectedComponentId + '{ border: 2px solid #0055ff; }'
selectedComponentStyle.appendChild(document.createTextNode(selectedCss))
styles = document.createElement('style')
document.head.appendChild(styles)
styles.appendChild(document.createTextNode(data.styles))
window["##BUDIBASE_FRONTEND_DEFINITION##"] = data.frontendDefinition;
if (clientModule) {
clientModule.loadBudibase({ window, localStorage })
}
}
let clientModule
let styles
let selectedComponentStyle
document.addEventListener("click", function(e) {
e.preventDefault()
e.stopPropagation()
return false;
}, true)
import('/_builder/budibase-client.esm.mjs') import('/_builder/budibase-client.esm.mjs')
.then(module => { .then(module => {
module.loadBudibase({ window, localStorage }); clientModule = module
window.addEventListener('message', receiveMessage)
window.dispatchEvent(new Event('bb-ready'))
}) })
</script> </script>
</head> </head>

View File

@ -1,6 +1,5 @@
<script> <script>
import { setContext, onMount } from "svelte" import { setContext, onMount } from "svelte"
import {screen, page} from "./propertyCategories.js"
import PropsView from "./PropsView.svelte" import PropsView from "./PropsView.svelte"
import { store } from "builderStore" import { store } from "builderStore"
import IconButton from "components/common/IconButton.svelte" import IconButton from "components/common/IconButton.svelte"
@ -31,6 +30,7 @@
let selectedCategory = categories[0] let selectedCategory = categories[0]
$: components = $store.components $: components = $store.components
$: componentInstance = $store.currentComponentInfo
$: componentDefinition = $store.components[componentInstance._component] $: componentDefinition = $store.components[componentInstance._component]
$: componentPropDefinition = $: componentPropDefinition =
flattenedPanel.find( flattenedPanel.find(
@ -38,7 +38,6 @@
c => c._component === componentInstance._component c => c._component === componentInstance._component
) || {} ) || {}
let panelDefinition = {} let panelDefinition = {}
$: { $: {
@ -58,17 +57,9 @@
} }
} }
$: componentInstance = $store.currentView !== "component" ? {...$store.currentPreviewItem, ...$store.currentComponentInfo} : $store.currentComponentInfo
const onStyleChanged = store.setComponentStyle const onStyleChanged = store.setComponentStyle
const onPropChanged = store.setComponentProp
function onPropChanged(key, value) {
if($store.currentView !== "component") {
store.editPageOrScreen(key, value)
return
}
store.setComponentProp(key, value)
}
function walkProps(component, action) { function walkProps(component, action) {
action(component) action(component)
@ -108,9 +99,9 @@
<DesignView {panelDefinition} {componentInstance} {onStyleChanged} /> <DesignView {panelDefinition} {componentInstance} {onStyleChanged} />
{:else if selectedCategory.value === 'settings'} {:else if selectedCategory.value === 'settings'}
<SettingsView <SettingsView
{panelDefinition}
{componentInstance} {componentInstance}
{componentDefinition} {componentDefinition}
{panelDefinition}
onChange={onPropChanged} /> onChange={onPropChanged} />
{:else if selectedCategory.value === 'events'} {:else if selectedCategory.value === 'events'}
<EventsEditor component={componentInstance} /> <EventsEditor component={componentInstance} />

View File

@ -1,6 +1,7 @@
<script> <script>
import { excludeProps } from "./propertyCategories.js" import { excludeProps } from "./propertyCategories.js"
import PropertyControl from "./PropertyControl.svelte" import PropertyControl from "./PropertyControl.svelte"
import { DetailSummary } from "@budibase/bbui"
export let name = "" export let name = ""
export let styleCategory = "normal" export let styleCategory = "normal"
@ -8,23 +9,10 @@
export let componentInstance = {} export let componentInstance = {}
export let onStyleChanged = () => {} export let onStyleChanged = () => {}
export let show = false
const capitalize = name => name[0].toUpperCase() + name.slice(1)
$: icon = show ? "ri-arrow-down-s-fill" : "ri-arrow-right-s-fill"
$: style = componentInstance["_styles"][styleCategory] || {} $: style = componentInstance["_styles"][styleCategory] || {}
</script> </script>
<div class="property-group-container"> <DetailSummary {name}>
<div class="property-group-name" on:click={() => (show = !show)}>
<div class="icon">
<i class={icon} />
</div>
<div class="name">{capitalize(name)}</div>
</div>
<div class="property-panel" class:show>
{#each properties as props} {#each properties as props}
<PropertyControl <PropertyControl
label={props.label} label={props.label}
@ -34,53 +22,4 @@
onChange={(key, value) => onStyleChanged(styleCategory, key, value)} onChange={(key, value) => onStyleChanged(styleCategory, key, value)}
props={{ ...excludeProps(props, ['control', 'label']) }} /> props={{ ...excludeProps(props, ['control', 'label']) }} />
{/each} {/each}
</div> </DetailSummary>
</div>
<style>
.property-group-container {
display: flex;
flex-direction: column;
height: auto;
background: var(--grey-light);
margin: 0px 0px 4px 0px;
padding: 8px 12px;
justify-content: center;
border-radius: 4px;
}
.property-group-name {
cursor: pointer;
display: flex;
flex-flow: row nowrap;
}
.name {
flex: 1;
text-align: left;
padding-top: 2px;
font-size: 14px;
font-weight: 500;
letter-spacing: 0.14px;
color: var(--ink);
}
.icon {
flex: 0 0 20px;
text-align: center;
}
.property-panel {
/* height: 0px;
overflow: hidden; */
display: none;
}
.show {
/* overflow: auto;
height: auto; */
display: flex;
flex-direction: column;
flex: 1;
}
</style>

View File

@ -9,10 +9,7 @@
export let componentInstance = {} export let componentInstance = {}
export let onChange = () => {} export let onChange = () => {}
const propExistsOnComponentDef = prop => prop in componentDefinition.props
let pageScreenProps = ["title","favicon", "description", "route"]
const propExistsOnComponentDef = prop => pageScreenProps.includes(prop) || prop in componentDefinition.props
function handleChange(key, data) { function handleChange(key, data) {
data.target ? onChange(key, data.target.value) : onChange(key, data) data.target ? onChange(key, data.target.value) : onChange(key, data)

View File

@ -2,16 +2,10 @@ import Input from "../common/Input.svelte"
import OptionSelect from "./OptionSelect.svelte" import OptionSelect from "./OptionSelect.svelte"
import InputGroup from "../common/Inputs/InputGroup.svelte" import InputGroup from "../common/Inputs/InputGroup.svelte"
import FlatButtonGroup from "./FlatButtonGroup.svelte" import FlatButtonGroup from "./FlatButtonGroup.svelte"
// import Colorpicker from "../common/Colorpicker.svelte"
export const screen = [ /*
{ label: "Description", key: "description", control: Input }, TODO: Allow for default values for all properties
{ label: "Route", key: "route", control: Input }, */
]
export const page = [
{ label: "Title", key: "title", control: Input },
{ label: "Favicon", key: "favicon", control: Input },
]
export const layout = [ export const layout = [
{ {
@ -90,7 +84,6 @@ export const spacing = [
key: "margin", key: "margin",
control: InputGroup, control: InputGroup,
meta: spacingMeta, meta: spacingMeta,
suffix: "px",
defaultValue: ["0", "0", "0", "0"], defaultValue: ["0", "0", "0", "0"],
}, },
{ {
@ -98,7 +91,6 @@ export const spacing = [
key: "padding", key: "padding",
control: InputGroup, control: InputGroup,
meta: spacingMeta, meta: spacingMeta,
suffix: "px",
defaultValue: ["0", "0", "0", "0"], defaultValue: ["0", "0", "0", "0"],
}, },
] ]
@ -109,7 +101,6 @@ export const size = [
key: "width", key: "width",
control: Input, control: Input,
placeholder: "px", placeholder: "px",
suffix: "px",
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
}, },
@ -118,7 +109,6 @@ export const size = [
key: "height", key: "height",
control: Input, control: Input,
placeholder: "px", placeholder: "px",
suffix: "px",
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
}, },
@ -127,7 +117,6 @@ export const size = [
key: "min-width", key: "min-width",
control: Input, control: Input,
placeholder: "px", placeholder: "px",
suffix: "px",
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
}, },
@ -135,7 +124,6 @@ export const size = [
label: "Min H", label: "Min H",
key: "min-height", key: "min-height",
control: Input, control: Input,
suffix: "px",
placeholder: "px", placeholder: "px",
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
@ -145,7 +133,6 @@ export const size = [
key: "max-width", key: "max-width",
control: Input, control: Input,
placeholder: "px", placeholder: "px",
suffix: "px",
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
}, },
@ -154,7 +141,6 @@ export const size = [
key: "max-height", key: "max-height",
control: Input, control: Input,
placeholder: "px", placeholder: "px",
suffix: "px",
width: "48px", width: "48px",
textAlign: "center", textAlign: "center",
}, },

View File

@ -62,7 +62,7 @@
<span <span
class:active={false} class:active={false}
class="topnavitemright" class="topnavitemright"
on:click={() => (location = `/${application}`)}> on:click={() => window.open(`/${application}`)}>
<PreviewIcon /> <PreviewIcon />
</span> </span>
</div> </div>

View File

@ -1,5 +1,6 @@
<script> <script>
import Modal from "svelte-simple-modal" import Modal from "svelte-simple-modal"
import { Home as Link } from "@budibase/bbui"
import { import {
SettingsIcon, SettingsIcon,
AppsIcon, AppsIcon,
@ -24,89 +25,29 @@
<div class="nav-section"> <div class="nav-section">
<div class="nav-section-title">Build</div> <div class="nav-section-title">Build</div>
<div class="nav-item-home"> <Link icon={AppsIcon} title="Apps" href="/" active />
<span class="nav-item-icon"> <Link icon={SettingsIcon} title="Settings" href="/" />
<AppsIcon /> <Link icon={UpdatesIcon} title="Updates" href="/" />
</span> <Link icon={HostingIcon} title="Hosting" href="/" />
<div class="nav-item-title">Apps</div>
</div>
<div class="nav-item">
<span class="nav-item-icon">
<SettingsIcon />
</span>
<div class="nav-item-title">Settings</div>
</div>
<a href="https://budibase.con/login" target="_blank" class="nav-item">
<span class="nav-item-icon">
<UpdatesIcon />
</span>
<div class="nav-item-title">Updates</div>
</a>
<a href="https://budibase.con/login" target="_blank" class="nav-item">
<span class="nav-item-icon">
<HostingIcon />
</span>
<div class="nav-item-title">Hosting</div>
</a>
</div> </div>
<div class="nav-section"> <div class="nav-section">
<div class="nav-section-title">Learn</div> <div class="nav-section-title">Learn</div>
<a href="https://docs.budibase.com/" target="_blank" class="nav-item"> <Link icon={DocumentationIcon} title="Documentation" href="/" />
<span class="nav-item-icon"> <Link icon={TutorialsIcon} title="Tutorials" href="/" />
<DocumentationIcon /> <Link icon={CommunityIcon} title="Community" href="/" />
</span> <Link icon={ContributionIcon} title="Contact" href="/" />
<div class="nav-item-title">Documentation</div>
</a>
<a
href="https://docs.budibase.com/tutorial/quick-start"
target="_blank"
class="nav-item">
<span class="nav-item-icon">
<TutorialsIcon />
</span>
<div class="nav-item-title">Tutorials</div>
</a>
<a href="https://forum.budibase.com/" target="_blank" class="nav-item">
<span class="nav-item-icon">
<CommunityIcon />
</span>
<div class="nav-item-title">Community</div>
</a>
</div> </div>
<div class="nav-section"> <div class="nav-section">
<div class="nav-section-title">Contact</div> <div class="nav-section-title">Contact</div>
<a <Link
href="https://github.com/Budibase/budibase/blob/master/CONTRIBUTING.md" icon={ContributionIcon}
target="_blank" title="Contribute to our product"
class="nav-item"> href="/" />
<span class="nav-item-icon"> <Link icon={BugIcon} title="Report bug" href="/" />
<ContributionIcon /> <Link icon={EmailIcon} title="Email" href="/" />
</span> <Link icon={TwitterIcon} title="Twitter" href="/" />
<div class="nav-item-title">Contribute to our product</div>
</a>
<a
href="https://github.com/Budibase/budibase/issues"
target="_blank"
class="nav-item">
<span class="nav-item-icon">
<BugIcon />
</span>
<div class="nav-item-title">Report bug</div>
</a>
<a href="mailto:support@budibase.com" target="_blank" class="nav-item">
<span class="nav-item-icon">
<EmailIcon />
</span>
<div class="nav-item-title">Email</div>
</a>
<a href="https://twitter.com/budibase" target="_blank" class="nav-item">
<span class="nav-item-icon">
<TwitterIcon />
</span>
<div class="nav-item-title">Twitter</div>
</a>
</div> </div>
</div> </div>
@ -160,48 +101,4 @@
font-weight: 700; font-weight: 700;
margin-bottom: 12px; margin-bottom: 12px;
} }
.nav-item {
cursor: pointer;
margin: 0px 0px 4px 0px;
padding: 0px 0px 0px 12px;
height: 40px;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
}
.nav-item-home {
cursor: pointer;
margin: 0px 0px 4px 0px;
padding: 0px 0px 0px 12px;
height: 40px;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
background-color: var(--blue-light);
}
.nav-item:hover {
background-color: var(--grey-light);
border-radius: 3px;
}
.nav-item::selection {
background-color: var(--blue-light);
border-radius: 3px;
}
.nav-item-title {
font-size: 14px;
color: var(--ink);
font-weight: 400;
margin-left: 12px;
}
.nav-item-icon {
color: var(--ink-light);
}
</style> </style>