forked from tsai/budibase
9 changed files with 451 additions and 10 deletions
|
After Width: | Height: | Size: 260 B |
|
After Width: | Height: | Size: 395 B |
|
After Width: | Height: | Size: 326 B |
@ -0,0 +1,3 @@ |
|||||
|
export { default as LayoutIcon } from './Layout.svelte'; |
||||
|
export { default as PaintIcon } from './Paint.svelte'; |
||||
|
export { default as TerminalIcon } from './Terminal.svelte'; |
||||
@ -0,0 +1,127 @@ |
|||||
|
<script> |
||||
|
let snippets = []; |
||||
|
let current_snippet = 0; |
||||
|
let snippet_text = '' |
||||
|
let id = 0; |
||||
|
|
||||
|
function save_snippet() { |
||||
|
if (!snippet_text) return; |
||||
|
|
||||
|
const index = snippets.findIndex(({ id }) => current_snippet === id); |
||||
|
|
||||
|
if (index > -1) { |
||||
|
snippets[index].snippet = snippet_text; |
||||
|
} else { |
||||
|
snippets = snippets.concat({ snippet: snippet_text , id: id }); |
||||
|
} |
||||
|
snippet_text = ''; |
||||
|
current_snippet = ++id; |
||||
|
} |
||||
|
|
||||
|
function edit_snippet(id) { |
||||
|
const { snippet, id: _id } = snippets.find(({ id:_id }) => _id === id); |
||||
|
current_snippet = id |
||||
|
snippet_text = snippet; |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<h3>Code</h3> |
||||
|
|
||||
|
<p>Use the code box below to add snippets of javascript to enhance your webapp</p> |
||||
|
|
||||
|
<div class="editor"> |
||||
|
<textarea bind:value={snippet_text} /> |
||||
|
<button on:click={save_snippet}>Save</button> |
||||
|
</div> |
||||
|
|
||||
|
<div class="snippets"> |
||||
|
<h3>Snippets added</h3> |
||||
|
{#each snippets as { id, snippet } } |
||||
|
<div class="snippet"> |
||||
|
<pre>{snippet}</pre> |
||||
|
<button on:click={() => edit_snippet(id)}>Edit</button> |
||||
|
</div> |
||||
|
{/each} |
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
h3 { |
||||
|
text-transform: uppercase; |
||||
|
font-size: 10px; |
||||
|
font-weight: 700; |
||||
|
color: #8997ab; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
p { |
||||
|
font-size: 12px; |
||||
|
color: #333; |
||||
|
margin-top: 0; |
||||
|
} |
||||
|
|
||||
|
.editor { |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.editor textarea { |
||||
|
width: 100%; |
||||
|
outline: none; |
||||
|
height: 150px; |
||||
|
border: none; |
||||
|
background: #173157; |
||||
|
border-radius: 5px; |
||||
|
box-sizing: border-box; |
||||
|
white-space: pre; |
||||
|
color: #eee; |
||||
|
padding: 10px; |
||||
|
font-family: monospace; |
||||
|
resize: none; |
||||
|
overflow-y: scroll; |
||||
|
} |
||||
|
|
||||
|
button { |
||||
|
position: absolute; |
||||
|
box-shadow: 0 0 black; |
||||
|
color: #eee; |
||||
|
right: 5px; |
||||
|
bottom: 10px; |
||||
|
background: none; |
||||
|
border: none; |
||||
|
text-transform: uppercase; |
||||
|
font-size: 9px; |
||||
|
font-weight: 600; |
||||
|
outline: none; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.snippets { |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
|
||||
|
.snippet { |
||||
|
position: relative; |
||||
|
margin-top: 5px; |
||||
|
} |
||||
|
|
||||
|
.snippet pre { |
||||
|
width: 100%; |
||||
|
outline: none; |
||||
|
max-height: 150px; |
||||
|
border: none; |
||||
|
background: #f9f9f9; |
||||
|
border-radius: 5px; |
||||
|
box-sizing: border-box; |
||||
|
white-space: pre; |
||||
|
color: #333; |
||||
|
padding: 10px; |
||||
|
font-family: monospace; |
||||
|
resize: none; |
||||
|
overflow-y: scroll; |
||||
|
margin: 10px; |
||||
|
} |
||||
|
|
||||
|
.snippet button { |
||||
|
color: #ccc; |
||||
|
} |
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,265 @@ |
|||||
|
<script> |
||||
|
|
||||
|
import PropsView from "./PropsView.svelte"; |
||||
|
import { store } from "../builderStore"; |
||||
|
import { isRootComponent } from "./pagesParsing/searchComponents"; |
||||
|
import IconButton from "../common/IconButton.svelte"; |
||||
|
import Textbox from "../common/Textbox.svelte"; |
||||
|
// import UIkit from "uikit"; |
||||
|
import { pipe } from "../common/core"; |
||||
|
import { |
||||
|
getScreenInfo |
||||
|
} from "./pagesParsing/createProps"; |
||||
|
// import Button from "../common/Button.svelte"; |
||||
|
// import ButtonGroup from "../common/ButtonGroup.svelte"; |
||||
|
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/'; |
||||
|
import CodeEditor from './CodeEditor.svelte'; |
||||
|
|
||||
|
import { |
||||
|
cloneDeep, |
||||
|
join, |
||||
|
split, |
||||
|
map, |
||||
|
keys, |
||||
|
isUndefined, |
||||
|
last |
||||
|
} from "lodash/fp"; |
||||
|
import { assign } from "lodash"; |
||||
|
|
||||
|
let component; |
||||
|
let name = ""; |
||||
|
let description = ""; |
||||
|
let tagsString = ""; |
||||
|
let nameInvalid = ""; |
||||
|
let componentInfo; |
||||
|
let modalElement |
||||
|
let propsValidationErrors = []; |
||||
|
let originalName=""; |
||||
|
let components; |
||||
|
let ignoreStore = false; |
||||
|
|
||||
|
$: shortName = last(name.split("/")); |
||||
|
|
||||
|
store.subscribe(s => { |
||||
|
if(ignoreStore) return; |
||||
|
component = s.currentFrontEndItem; |
||||
|
if(!component) return; |
||||
|
originalName = component.name; |
||||
|
name = component.name; |
||||
|
description = component.description; |
||||
|
tagsString = join(", ")(component.tags); |
||||
|
componentInfo = s.currentComponentInfo; |
||||
|
components = s.components; |
||||
|
}); |
||||
|
|
||||
|
// const save = () => { |
||||
|
|
||||
|
// ignoreStore = true; |
||||
|
// if(!validate()) { |
||||
|
// ignoreStore = false; |
||||
|
// return; |
||||
|
// } |
||||
|
|
||||
|
// component.name = originalName || name; |
||||
|
// component.description = description; |
||||
|
// component.tags = pipe(tagsString, [ |
||||
|
// split(","), |
||||
|
// map(s => s.trim()) |
||||
|
// ]); |
||||
|
|
||||
|
// store.saveScreen(component); |
||||
|
|
||||
|
// ignoreStore = false; |
||||
|
// // now do the rename |
||||
|
// if(name !== originalName) { |
||||
|
// store.renameScreen(originalName, name); |
||||
|
// } |
||||
|
// } |
||||
|
|
||||
|
// const deleteComponent = () => { |
||||
|
// showDialog(); |
||||
|
// } |
||||
|
|
||||
|
// const confirmDeleteComponent = () => { |
||||
|
// store.deleteScreen(component.name); |
||||
|
// hideDialog(); |
||||
|
// } |
||||
|
|
||||
|
const onPropsValidate = result => { |
||||
|
propsValidationErrors = result; |
||||
|
} |
||||
|
|
||||
|
const updateComponent = doChange => { |
||||
|
const newComponent = cloneDeep(component); |
||||
|
doChange(newComponent); |
||||
|
component = newComponent; |
||||
|
componentInfo = getScreenInfo(components, newComponent); |
||||
|
} |
||||
|
|
||||
|
const onPropsChanged = newProps => { |
||||
|
updateComponent(newComponent => |
||||
|
assign(newComponent.props, newProps)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
const validate = () => { |
||||
|
const fieldInvalid = (field, err) => |
||||
|
errors[field] = err; |
||||
|
const fieldValid = field => |
||||
|
errors[field] && delete errors[field]; |
||||
|
|
||||
|
if(!name) nameInvalid = "component name i not supplied"; |
||||
|
else nameInvalid = ""; |
||||
|
|
||||
|
return (!nameInvalid && propsValidationErrors.length === 0); |
||||
|
} |
||||
|
|
||||
|
// const hideDialog = () => { |
||||
|
// UIkit.modal(modalElement).hide(); |
||||
|
// } |
||||
|
|
||||
|
// const showDialog = () => { |
||||
|
// UIkit.modal(modalElement).show(); |
||||
|
// } |
||||
|
|
||||
|
let current_view = 'props'; |
||||
|
|
||||
|
|
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<div class="root"> |
||||
|
|
||||
|
<!-- <div class="title"> |
||||
|
<div>{shortName}</div> |
||||
|
<div> |
||||
|
<IconButton icon="save" |
||||
|
on:click={save} |
||||
|
color="var(--secondary100)" |
||||
|
hoverColor="var(--primary100)"/> |
||||
|
<IconButton icon="trash" |
||||
|
on:click={deleteComponent} |
||||
|
color="var(--secondary100)" |
||||
|
hoverColor="var(--primary100)"/> |
||||
|
</div> |
||||
|
</div> --> |
||||
|
|
||||
|
<ul> |
||||
|
<li> |
||||
|
<button class:selected={current_view === 'props'} on:click={() => current_view = 'props'}> |
||||
|
<PaintIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
<li> |
||||
|
<button class:selected={current_view === 'layout'} on:click={() => current_view = 'layout'}> |
||||
|
<LayoutIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
<li> |
||||
|
<button class:selected={current_view === 'code'} on:click={() => current_view = 'code'}> |
||||
|
<TerminalIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
</ul> |
||||
|
|
||||
|
<div class="component-props-container"> |
||||
|
|
||||
|
{#if current_view === 'props'} |
||||
|
<PropsView onValidate={onPropsValidate} |
||||
|
{componentInfo} |
||||
|
{onPropsChanged} /> |
||||
|
{:else if current_view === 'layout'} |
||||
|
<p>Layout</p> |
||||
|
{:else} |
||||
|
<CodeEditor /> |
||||
|
{/if} |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
<!-- <div bind:this={modalElement} uk-modal> |
||||
|
<div class="uk-modal-dialog"> |
||||
|
|
||||
|
<div class="uk-modal-header"> |
||||
|
Delete {name} ? |
||||
|
</div> |
||||
|
|
||||
|
<div class="uk-modal-body"> |
||||
|
Are you sure you want to delete this component ? |
||||
|
</div> |
||||
|
|
||||
|
<div class="uk-modal-footer"> |
||||
|
<ButtonGroup> |
||||
|
<Button grouped |
||||
|
on:click={confirmDeleteComponent}> |
||||
|
OK |
||||
|
</Button> |
||||
|
<Button grouped |
||||
|
on:click={hideDialog} |
||||
|
color="secondary" > |
||||
|
Cancel |
||||
|
</Button> |
||||
|
</ButtonGroup> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
</div> --> |
||||
|
|
||||
|
<style> |
||||
|
|
||||
|
.root { |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.title > div:nth-child(1) { |
||||
|
grid-column-start: name; |
||||
|
color: var(--secondary100); |
||||
|
} |
||||
|
|
||||
|
.title > div:nth-child(2) { |
||||
|
grid-column-start: actions; |
||||
|
} |
||||
|
|
||||
|
.component-props-container { |
||||
|
margin-top: 10px; |
||||
|
flex: 1 1 auto; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
|
||||
|
ul { |
||||
|
list-style: none; |
||||
|
display: flex; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
li { |
||||
|
margin-right: 20px; |
||||
|
background: none; |
||||
|
border-radius: 5px; |
||||
|
width: 45px; |
||||
|
height: 45px; |
||||
|
} |
||||
|
|
||||
|
li button { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
background: none; |
||||
|
border: none; |
||||
|
border-radius: 5px; |
||||
|
padding: 12px; |
||||
|
outline: none; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.selected { |
||||
|
color: var(--button-text); |
||||
|
background: var(--background-button)!important; |
||||
|
} |
||||
|
|
||||
|
</style> |
||||
Loading…
Reference in new issue