forked from tsai/budibase
11 changed files with 391 additions and 814 deletions
@ -1,95 +1,85 @@ |
|||||
<script> |
<script> |
||||
import { store } from "../builderStore" |
import { store } from "../builderStore"; |
||||
import { map, join } from "lodash/fp" |
import { map, join } from "lodash/fp"; |
||||
import { pipe } from "../common/core" |
import { pipe } from "../common/core"; |
||||
|
import { buildPropsHierarchy } from "./pagesParsing/buildPropsHierarchy"; |
||||
|
|
||||
let iframe |
let iframe; |
||||
|
|
||||
function transform_component(comp) { |
$: iframe && console.log(iframe.contentDocument.head.insertAdjacentHTML('beforeend', '<style></style>')) |
||||
const props = comp.props || comp |
$: hasComponent = !!$store.currentFrontEndItem; |
||||
if (props && props._children && props._children.length) { |
$: styles = hasComponent ? $store.currentFrontEndItem._css : ''; |
||||
props._children = props._children.map(transform_component) |
|
||||
} |
|
||||
|
|
||||
return props |
|
||||
} |
|
||||
|
|
||||
$: iframe && |
|
||||
console.log( |
|
||||
iframe.contentDocument.head.insertAdjacentHTML( |
|
||||
"beforeend", |
|
||||
`<\style></style>` |
|
||||
) |
|
||||
) |
|
||||
$: hasComponent = !!$store.currentPreviewItem |
|
||||
$: styles = hasComponent ? $store.currentPreviewItem._css : "" |
|
||||
|
|
||||
$: stylesheetLinks = pipe( |
|
||||
$store.pages.stylesheets, |
|
||||
[map(s => `<link rel="stylesheet" href="${s}"/>`), join("\n")] |
|
||||
) |
|
||||
|
|
||||
$: frontendDefinition = { |
$: stylesheetLinks = pipe($store.pages.stylesheets, [ |
||||
componentLibraries: $store.loadLibraryUrls(), |
map(s => `<link rel="stylesheet" href="${s}"/>`), |
||||
page: $store.currentPreviewItem, |
join("\n") |
||||
screens: [], |
]); |
||||
appRootPath: "", |
|
||||
} |
|
||||
|
|
||||
$: backendDefinition = { |
|
||||
hierarchy: $store.hierarchy, |
|
||||
} |
|
||||
|
|
||||
|
$: appDefinition = { |
||||
|
componentLibraries: $store.loadLibraryUrls(), |
||||
|
props: buildPropsHierarchy( |
||||
|
$store.components, |
||||
|
$store.screens, |
||||
|
$store.currentFrontEndItem), |
||||
|
hierarchy: $store.hierarchy, |
||||
|
appRootPath: "" |
||||
|
}; |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
|
|
||||
<div class="component-container"> |
<div class="component-container"> |
||||
{#if hasComponent && $store.currentPreviewItem} |
{#if hasComponent} |
||||
<iframe |
<iframe style="height: 100%; width: 100%" |
||||
style="height: 100%; width: 100%" |
title="componentPreview" |
||||
title="componentPreview" |
bind:this={iframe} |
||||
bind:this={iframe} |
srcdoc={ |
||||
srcdoc={`<html> |
`<html> |
||||
<head> |
|
||||
${stylesheetLinks} |
|
||||
<style> |
|
||||
${styles || ''} |
|
||||
body, html { |
|
||||
height: 100%!important; |
|
||||
} |
|
||||
<\/style> |
|
||||
<\script> |
|
||||
window["##BUDIBASE_FRONTEND_DEFINITION##"] = ${JSON.stringify(frontendDefinition)}; |
|
||||
window["##BUDIBASE_BACKEND_DEFINITION##"] = ${JSON.stringify(backendDefinition)}; |
|
||||
window["##BUDIBASE_FRONTEND_FUNCTIONS##"] = ${$store.currentScreenFunctions}; |
|
||||
|
|
||||
|
<head> |
||||
|
${stylesheetLinks} |
||||
|
<script> |
||||
|
window["##BUDIBASE_APPDEFINITION##"] = ${JSON.stringify(appDefinition)}; |
||||
|
window["##BUDIBASE_UIFUNCTIONS"] = ${$store.currentScreenFunctions}; |
||||
|
|
||||
import('/_builder/budibase-client.esm.mjs') |
import('/_builder/budibase-client.esm.mjs') |
||||
.then(module => { |
.then(module => { |
||||
module.loadBudibase({ window, localStorage }); |
module.loadBudibase({ window, localStorage }); |
||||
}) |
}) |
||||
<\/script> |
</script> |
||||
</head> |
<style> |
||||
<body> |
|
||||
</body> |
body { |
||||
</html>`} /> |
box-sizing: border-box; |
||||
{/if} |
padding: 20px; |
||||
|
} |
||||
|
${styles} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
</body> |
||||
|
</html>`}> |
||||
|
</iframe> |
||||
|
{/if} |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
.component-container { |
.component-container { |
||||
grid-row-start: middle; |
grid-row-start: middle; |
||||
grid-column-start: middle; |
grid-column-start: middle; |
||||
position: relative; |
position: relative; |
||||
overflow: hidden; |
overflow: hidden; |
||||
padding-top: 56.25%; |
padding-top: 56.25%; |
||||
margin: auto; |
margin: auto; |
||||
} |
} |
||||
|
|
||||
.component-container iframe { |
.component-container iframe { |
||||
border: 0; |
border: 0; |
||||
height: 100%; |
height: 100%; |
||||
left: 0; |
left: 0; |
||||
position: absolute; |
position: absolute; |
||||
top: 0; |
top: 0; |
||||
width: 100%; |
width: 100%; |
||||
} |
} |
||||
</style> |
</style> |
||||
@ -0,0 +1,188 @@ |
|||||
|
<script> |
||||
|
import { ArrowDownIcon } from "../common/Icons/"; |
||||
|
import { store } from "../builderStore"; |
||||
|
import { isBinding, getBinding, setBinding } from "../common/binding"; |
||||
|
|
||||
|
export let value = ""; |
||||
|
export let onChanged = () => {}; |
||||
|
export let type = ""; |
||||
|
|
||||
|
let isOpen = false; |
||||
|
let stateBindings = []; |
||||
|
|
||||
|
let isBound = false; |
||||
|
let bindingPath = ""; |
||||
|
let bindingFallbackValue = ""; |
||||
|
let bindingSource = "store"; |
||||
|
let isExpanded = false; |
||||
|
let forceIsBound = false; |
||||
|
let canOnlyBind = false; |
||||
|
|
||||
|
$: { |
||||
|
canOnlyBind = type === "state"; |
||||
|
if (!forceIsBound && canOnlyBind) forceIsBound = true; |
||||
|
|
||||
|
isBound = forceIsBound || isBinding(value); |
||||
|
|
||||
|
if (isBound) { |
||||
|
const binding = getBinding(value); |
||||
|
bindingPath = binding.path; |
||||
|
bindingFallbackValue = binding.fallback; |
||||
|
bindingSource = binding.source || "store"; |
||||
|
} else { |
||||
|
bindingPath = ""; |
||||
|
bindingFallbackValue = ""; |
||||
|
bindingSource = "store"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const clearBinding = () => { |
||||
|
forceIsBound = false; |
||||
|
onChanged(""); |
||||
|
}; |
||||
|
|
||||
|
const bind = (path, fallback, source) => { |
||||
|
if (!path) { |
||||
|
clearBinding(""); |
||||
|
return; |
||||
|
} |
||||
|
const binding = setBinding({ path, fallback, source }); |
||||
|
onChanged(binding); |
||||
|
}; |
||||
|
|
||||
|
const setBindingPath = value => { |
||||
|
forceIsBound = canOnlyBind; |
||||
|
bind(value, bindingFallbackValue, bindingSource); |
||||
|
}; |
||||
|
|
||||
|
const setBindingFallback = value => bind(bindingPath, value, bindingSource); |
||||
|
|
||||
|
const setBindingSource = value => |
||||
|
bind(bindingPath, bindingFallbackValue, value); |
||||
|
|
||||
|
$: { |
||||
|
console.log({ |
||||
|
bindingFallbackValue, |
||||
|
bindingPath, |
||||
|
value |
||||
|
}); |
||||
|
|
||||
|
const currentScreen = $store.screens.find( |
||||
|
({ name }) => name === $store.currentFrontEndItem.name |
||||
|
); |
||||
|
stateBindings = currentScreen ? currentScreen.stateOrigins : []; |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<div class="cascader"> |
||||
|
<div class="input-box"> |
||||
|
<input |
||||
|
class="uk-input uk-form-small" |
||||
|
value={bindingFallbackValue} |
||||
|
on:change={e => { |
||||
|
setBindingFallback(e.target.value) |
||||
|
}}/> |
||||
|
<button on:click={() => (isOpen = !isOpen)}> |
||||
|
<span |
||||
|
class="icon" |
||||
|
style={` |
||||
|
transform: rotate(${isOpen ? 0 : 90}deg); |
||||
|
color: ${bindingPath ? 'rgba(0, 85, 255, 0.8)' : 'inherit'} |
||||
|
`}> |
||||
|
<ArrowDownIcon size={36} /> |
||||
|
</span> |
||||
|
</button> |
||||
|
</div> |
||||
|
{#if isOpen} |
||||
|
<ul class="options"> |
||||
|
{#each Object.keys(stateBindings) as stateBinding} |
||||
|
<li |
||||
|
style={`font-weight: ${stateBinding === bindingPath ? 'bold' : 'initial'}`} |
||||
|
on:click={() => { |
||||
|
setBindingPath(stateBinding === bindingPath ? null : stateBinding); |
||||
|
}}> |
||||
|
{stateBinding} |
||||
|
</li> |
||||
|
{/each} |
||||
|
</ul> |
||||
|
{/if} |
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
button { |
||||
|
cursor: pointer; |
||||
|
outline: none; |
||||
|
border: none; |
||||
|
border-radius: 5px; |
||||
|
background: rgba(249, 249, 249, 1); |
||||
|
|
||||
|
width: 30px; |
||||
|
height: 30px; |
||||
|
padding-bottom: 10px; |
||||
|
|
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
|
||||
|
font-size: 1.6rem; |
||||
|
font-weight: 700; |
||||
|
color: rgba(22, 48, 87, 1); |
||||
|
} |
||||
|
|
||||
|
.cascader { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.input-box { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.options { |
||||
|
width: 172px; |
||||
|
margin: 0; |
||||
|
position: absolute; |
||||
|
top: 35px; |
||||
|
padding: 10px; |
||||
|
z-index: 1; |
||||
|
background: rgba(249, 249, 249, 1); |
||||
|
min-height: 50px; |
||||
|
border-radius: 2px; |
||||
|
} |
||||
|
|
||||
|
li { |
||||
|
list-style-type: none; |
||||
|
transition: 0.2s all; |
||||
|
} |
||||
|
|
||||
|
li:hover { |
||||
|
cursor: pointer; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
input { |
||||
|
margin-right: 5px; |
||||
|
border: 1px solid #dbdbdb; |
||||
|
border-radius: 2px; |
||||
|
opacity: 0.5; |
||||
|
height: 40px; |
||||
|
/* display: block; |
||||
|
font-size: 14px; |
||||
|
font-family: sans-serif; |
||||
|
font-weight: 500; |
||||
|
color: #163057; |
||||
|
line-height: 1.3; |
||||
|
padding: 1em 2.6em 0.9em 1.4em; |
||||
|
/* width: 100%; */ |
||||
|
/* max-width: 100%; |
||||
|
box-sizing: border-box; |
||||
|
margin: 0; |
||||
|
-moz-appearance: none; |
||||
|
-webkit-appearance: none; |
||||
|
appearance: none; |
||||
|
background: #fff; |
||||
|
border: 1px solid #ccc; |
||||
|
height: 50px; */ |
||||
|
} |
||||
|
</style> |
||||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue