Merge branch 'master' into colorpicker/swatch-updates
This commit is contained in:
commit
4388a4a542
24 changed files with 172 additions and 165 deletions
BIN
packages/builder/assets/orange-landscape.png
Normal file
BIN
packages/builder/assets/orange-landscape.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 MiB |
Binary file not shown.
Before Width: | Height: | Size: 201 KiB |
Binary file not shown.
Before Width: | Height: | Size: 105 KiB |
|
@ -55,7 +55,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@budibase/bbui": "^1.15.0",
|
"@budibase/bbui": "^1.15.4",
|
||||||
"@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",
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
/* Budibase Component Styles */
|
/* Budibase Component Styles */
|
||||||
.header {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--ink);
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-top: 1rem;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.budibase__title {
|
.budibase__title {
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
|
|
|
@ -29,7 +29,8 @@ import {
|
||||||
export const getStore = () => {
|
export const getStore = () => {
|
||||||
const initial = {
|
const initial = {
|
||||||
apps: [],
|
apps: [],
|
||||||
appname: "",
|
name: "",
|
||||||
|
description: "",
|
||||||
pages: DEFAULT_PAGES_OBJECT,
|
pages: DEFAULT_PAGES_OBJECT,
|
||||||
mainUi: {},
|
mainUi: {},
|
||||||
unauthenticatedUi: {},
|
unauthenticatedUi: {},
|
||||||
|
@ -101,7 +102,8 @@ const setPackage = (store, initial) => async pkg => {
|
||||||
|
|
||||||
initial.libraries = pkg.application.componentLibraries
|
initial.libraries = pkg.application.componentLibraries
|
||||||
initial.components = await fetchComponentLibDefinitions(pkg.application._id)
|
initial.components = await fetchComponentLibDefinitions(pkg.application._id)
|
||||||
initial.appname = pkg.application.name
|
initial.name = pkg.application.name
|
||||||
|
initial.description = pkg.application.description
|
||||||
initial.appId = pkg.application._id
|
initial.appId = pkg.application._id
|
||||||
initial.pages = pkg.pages
|
initial.pages = pkg.pages
|
||||||
initial.hasAppPackage = true
|
initial.hasAppPackage = true
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$: currentAppInfo = {
|
$: currentAppInfo = {
|
||||||
appname: $store.appname,
|
name: $store.name,
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUsers() {
|
async function fetchUsers() {
|
||||||
|
|
|
@ -1,15 +1,39 @@
|
||||||
<script>
|
<script>
|
||||||
import { Input, TextArea, Button } from "@budibase/bbui"
|
import { Input, TextArea, Button } from "@budibase/bbui"
|
||||||
|
import { store } from "builderStore"
|
||||||
|
import api from "builderStore/api"
|
||||||
import Title from "../TabTitle.svelte"
|
import Title from "../TabTitle.svelte"
|
||||||
|
|
||||||
|
async function updateApplication(data) {
|
||||||
|
const response = await api.put(`/api/${$store.appId}`, data)
|
||||||
|
const app = await response.json()
|
||||||
|
store.update(state => {
|
||||||
|
state = {
|
||||||
|
...state,
|
||||||
|
...data,
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Title>General</Title>
|
<Title>General</Title>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="background">
|
<div class="background">
|
||||||
<Input thin edit placeholder="Enter your name" label="Name" />
|
<Input
|
||||||
|
on:save={e => updateApplication({ name: e.detail })}
|
||||||
|
thin
|
||||||
|
edit
|
||||||
|
value={$store.name}
|
||||||
|
label="Name" />
|
||||||
</div>
|
</div>
|
||||||
<div class="background">
|
<div class="background">
|
||||||
<TextArea thin edit placeholder="Enter your name" label="Name" />
|
<TextArea
|
||||||
|
on:save={e => updateApplication({ description: e.detail })}
|
||||||
|
thin
|
||||||
|
edit
|
||||||
|
value={$store.description}
|
||||||
|
label="Name" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<style>
|
<style>
|
||||||
.apps {
|
.apps {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, 380px);
|
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
|
||||||
grid-gap: 20px 40px;
|
grid-gap: 20px 40px;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<AppsIcon />
|
<AppsIcon />
|
||||||
</span>
|
</span>
|
||||||
<h3>Create new web app</h3>
|
<h3 class="header">Create new web app</h3>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
name="name"
|
name="name"
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
<InfoIcon />
|
<InfoIcon />
|
||||||
How to get started
|
How to get started
|
||||||
</a>
|
</a>
|
||||||
<Button outline thin on:click={_onCancel}>Cancel</Button>
|
<Button secondary thin on:click={_onCancel}>Cancel</Button>
|
||||||
<Button primary thin on:click={_onOkay}>Save</Button>
|
<Button primary thin on:click={_onOkay}>Save</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="close-button" on:click={_onCancel}>
|
<div class="close-button" on:click={_onCancel}>
|
||||||
|
@ -125,10 +125,11 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
h3 {
|
.header {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
|
font-family: inter;
|
||||||
}
|
}
|
||||||
.icon {
|
.icon {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
export let value = "#3ec1d3ff"
|
export let value = "#3ec1d3ff"
|
||||||
export let open = false
|
export let open = false
|
||||||
export let swatches = []
|
export let swatches = []
|
||||||
|
|
||||||
export let disableSwatches = false
|
export let disableSwatches = false
|
||||||
export let format = "hexa"
|
export let format = "hexa"
|
||||||
export let style = ""
|
export let style = ""
|
||||||
|
@ -176,6 +177,7 @@
|
||||||
$: border = v > 90 && s < 5 ? "1px dashed #dedada" : ""
|
$: border = v > 90 && s < 5 ? "1px dashed #dedada" : ""
|
||||||
$: selectedColorStyle = buildStyle({ background: value, border })
|
$: selectedColorStyle = buildStyle({ background: value, border })
|
||||||
$: hasSwatches = swatches.length > 0
|
$: hasSwatches = swatches.length > 0
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Portal>
|
<Portal>
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
export let target = document.body;
|
export let target = document.body
|
||||||
|
|
||||||
let targetEl;
|
let targetEl
|
||||||
let portal;
|
let portal
|
||||||
let componentInstance;
|
let componentInstance
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (typeof target === "string") {
|
if (typeof target === "string") {
|
||||||
targetEl = document.querySelector(target);
|
targetEl = document.querySelector(target)
|
||||||
// Force exit
|
// Force exit
|
||||||
if (targetEl === null) {
|
if (targetEl === null) {
|
||||||
return () => {};
|
return () => {}
|
||||||
}
|
}
|
||||||
} else if (target instanceof HTMLElement) {
|
} else if (target instanceof HTMLElement) {
|
||||||
targetEl = target;
|
targetEl = target
|
||||||
} else {
|
} else {
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
`Unknown target type: ${typeof target}. Allowed types: String (CSS selector), HTMLElement.`
|
`Unknown target type: ${typeof target}. Allowed types: String (CSS selector), HTMLElement.`
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
portal = document.createElement("div");
|
portal = document.createElement("div")
|
||||||
targetEl.appendChild(portal);
|
targetEl.appendChild(portal)
|
||||||
portal.appendChild(componentInstance);
|
portal.appendChild(componentInstance)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
targetEl.removeChild(portal);
|
targetEl.removeChild(portal)
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={componentInstance}>
|
<div bind:this={componentInstance}>
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import PropertyGroup from "./PropertyGroup.svelte"
|
import PropertyGroup from "./PropertyGroup.svelte"
|
||||||
import FlatButtonGroup from "./FlatButtonGroup.svelte"
|
import FlatButtonGroup from "./FlatButtonGroup.svelte"
|
||||||
|
|
||||||
|
|
||||||
export let panelDefinition = {}
|
export let panelDefinition = {}
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let componentDefinition = {}
|
export let componentDefinition = {}
|
||||||
|
@ -34,7 +33,6 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
$: propertyGroupNames = Object.keys(panelDefinition)
|
$: propertyGroupNames = Object.keys(panelDefinition)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="design-view-container">
|
<div class="design-view-container">
|
||||||
|
@ -55,7 +53,7 @@
|
||||||
{componentDefinition}
|
{componentDefinition}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
open={currentGroup === groupName}
|
open={currentGroup === groupName}
|
||||||
on:open={() => currentGroup = groupName} />
|
on:open={() => (currentGroup = groupName)} />
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="no-design">
|
<div class="no-design">
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
let selectMenu
|
let selectMenu
|
||||||
let icon
|
let icon
|
||||||
|
|
||||||
let selectAnchor = null;
|
let selectAnchor = null
|
||||||
let dimensions = { top: 0, bottom: 0, left: 0 }
|
let dimensions = { top: 0, bottom: 0, left: 0 }
|
||||||
|
|
||||||
let positionSide = "top"
|
let positionSide = "top"
|
||||||
let maxHeight = 0
|
let maxHeight = 0
|
||||||
let scrollTop = 0;
|
let scrollTop = 0
|
||||||
let containerEl = null;
|
let containerEl = null
|
||||||
|
|
||||||
const handleStyleBind = value =>
|
const handleStyleBind = value =>
|
||||||
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
|
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
|
||||||
|
@ -32,7 +32,6 @@
|
||||||
return () => {
|
return () => {
|
||||||
select.removeEventListener("keydown", handleEnter)
|
select.removeEventListener("keydown", handleEnter)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function handleEscape(e) {
|
function handleEscape(e) {
|
||||||
|
@ -42,15 +41,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDimensions() {
|
function getDimensions() {
|
||||||
const { bottom, top: spaceAbove, left } = selectAnchor.getBoundingClientRect()
|
const {
|
||||||
|
bottom,
|
||||||
|
top: spaceAbove,
|
||||||
|
left,
|
||||||
|
} = selectAnchor.getBoundingClientRect()
|
||||||
const spaceBelow = window.innerHeight - bottom
|
const spaceBelow = window.innerHeight - bottom
|
||||||
|
|
||||||
let y;
|
let y
|
||||||
|
|
||||||
if (spaceAbove > spaceBelow) {
|
if (spaceAbove > spaceBelow) {
|
||||||
positionSide = "bottom"
|
positionSide = "bottom"
|
||||||
maxHeight = spaceAbove - 20
|
maxHeight = spaceAbove - 20
|
||||||
y = (window.innerHeight - spaceAbove)
|
y = window.innerHeight - spaceAbove
|
||||||
} else {
|
} else {
|
||||||
positionSide = "top"
|
positionSide = "top"
|
||||||
y = bottom
|
y = bottom
|
||||||
|
@ -76,17 +79,17 @@
|
||||||
open = isOpen
|
open = isOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleClick(val) {
|
function handleClick(val) {
|
||||||
value = val
|
value = val
|
||||||
onChange(value)
|
onChange(value)
|
||||||
|
toggleSelect(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
$: menuStyle = buildStyle({
|
$: menuStyle = buildStyle({
|
||||||
"max-height": `${maxHeight.toFixed(0)}px`,
|
"max-height": `${maxHeight.toFixed(0)}px`,
|
||||||
"transform-origin": `center ${positionSide}`,
|
"transform-origin": `center ${positionSide}`,
|
||||||
[positionSide]: `${dimensions[positionSide]}px`,
|
[positionSide]: `${dimensions[positionSide]}px`,
|
||||||
"left": `${dimensions.left.toFixed(0)}px`,
|
left: `${dimensions.left.toFixed(0)}px`,
|
||||||
})
|
})
|
||||||
|
|
||||||
$: isOptionsObject = options.every(o => typeof o === "object")
|
$: isOptionsObject = options.every(o => typeof o === "object")
|
||||||
|
@ -108,7 +111,7 @@
|
||||||
bind:this={select}
|
bind:this={select}
|
||||||
class="bb-select-container"
|
class="bb-select-container"
|
||||||
on:click={() => toggleSelect(!open)}>
|
on:click={() => toggleSelect(!open)}>
|
||||||
<div bind:this={selectAnchor} class="bb-select-anchor selected">
|
<div bind:this={selectAnchor} title={value} class="bb-select-anchor selected">
|
||||||
<span>{displayLabel}</span>
|
<span>{displayLabel}</span>
|
||||||
<i bind:this={icon} class="ri-arrow-down-s-fill" />
|
<i bind:this={icon} class="ri-arrow-down-s-fill" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -174,6 +177,7 @@
|
||||||
background-color: var(--grey-2);
|
background-color: var(--grey-2);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bb-select-anchor > span {
|
.bb-select-anchor > span {
|
||||||
|
|
|
@ -38,7 +38,9 @@
|
||||||
if (!activeTopNav) return
|
if (!activeTopNav) return
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
if (!state.previousTopNavPath) state.previousTopNavPath = {}
|
if (!state.previousTopNavPath) state.previousTopNavPath = {}
|
||||||
state.previousTopNavPath[activeTopNav.path] = window.location.pathname.replace("/_builder", "")
|
state.previousTopNavPath[
|
||||||
|
activeTopNav.path
|
||||||
|
] = window.location.pathname.replace("/_builder", "")
|
||||||
$goto(state.previousTopNavPath[path] || path)
|
$goto(state.previousTopNavPath[path] || path)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,12 +3,13 @@ import { params } from "@sveltech/routify"
|
||||||
import { backendUiStore } from "builderStore"
|
import { backendUiStore } from "builderStore"
|
||||||
|
|
||||||
if ($params.selectedModel) {
|
if ($params.selectedModel) {
|
||||||
const model = $backendUiStore.models.find(m => m._id === $params.selectedModel)
|
const model = $backendUiStore.models.find(
|
||||||
|
m => m._id === $params.selectedModel
|
||||||
|
)
|
||||||
if (model) {
|
if (model) {
|
||||||
backendUiStore.actions.models.select(model)
|
backendUiStore.actions.models.select(model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -10,7 +10,11 @@
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// navigate to first model in list, if not already selected
|
// navigate to first model in list, if not already selected
|
||||||
// and this is the final url (i.e. no selectedModel)
|
// and this is the final url (i.e. no selectedModel)
|
||||||
if (!$leftover && $backendUiStore.models.length > 0 && (!$backendUiStore.selectedModel || !$backendUiStore.selectedModel._id)) {
|
if (
|
||||||
|
!$leftover &&
|
||||||
|
$backendUiStore.models.length > 0 &&
|
||||||
|
(!$backendUiStore.selectedModel || !$backendUiStore.selectedModel._id)
|
||||||
|
) {
|
||||||
$goto(`./${$backendUiStore.models[0]._id}`)
|
$goto(`./${$backendUiStore.models[0]._id}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,7 +10,11 @@
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// navigate to first model in list, if not already selected
|
// navigate to first model in list, if not already selected
|
||||||
// and this is the final url (i.e. no selectedModel)
|
// and this is the final url (i.e. no selectedModel)
|
||||||
if (!$leftover && $backendUiStore.models.length > 0 && (!$backendUiStore.selectedModel || !$backendUiStore.selectedModel._id)) {
|
if (
|
||||||
|
!$leftover &&
|
||||||
|
$backendUiStore.models.length > 0 &&
|
||||||
|
(!$backendUiStore.selectedModel || !$backendUiStore.selectedModel._id)
|
||||||
|
) {
|
||||||
// this file routes as .../models/index, so, go up one.
|
// this file routes as .../models/index, so, go up one.
|
||||||
$goto(`../${$backendUiStore.models[0]._id}`)
|
$goto(`../${$backendUiStore.models[0]._id}`)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +23,4 @@
|
||||||
|
|
||||||
{#if $backendUiStore.models.length === 0}
|
{#if $backendUiStore.models.length === 0}
|
||||||
Please create a model
|
Please create a model
|
||||||
{:else}
|
{:else}Please select a model{/if}
|
||||||
Please select a model
|
|
||||||
{/if}
|
|
||||||
|
|
|
@ -40,10 +40,7 @@
|
||||||
|
|
||||||
<div class="nav-section">
|
<div class="nav-section">
|
||||||
<div class="nav-section-title">Contact</div>
|
<div class="nav-section-title">Contact</div>
|
||||||
<Link
|
<Link icon={ContributionIcon} title="Contribute" href="/" />
|
||||||
icon={ContributionIcon}
|
|
||||||
title="Contribute to our product"
|
|
||||||
href="/" />
|
|
||||||
<Link icon={BugIcon} title="Report bug" href="/" />
|
<Link icon={BugIcon} title="Report bug" href="/" />
|
||||||
<Link icon={EmailIcon} title="Email" href="/" />
|
<Link icon={EmailIcon} title="Email" href="/" />
|
||||||
<Link icon={TwitterIcon} title="Twitter" href="/" />
|
<Link icon={TwitterIcon} title="Twitter" href="/" />
|
||||||
|
@ -59,7 +56,7 @@
|
||||||
<style>
|
<style>
|
||||||
.root {
|
.root {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 300px 1fr;
|
grid-template-columns: 260px 1fr;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--grey-1);
|
background: var(--grey-1);
|
||||||
|
@ -67,6 +64,7 @@
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-nav {
|
.ui-nav {
|
||||||
|
@ -75,7 +73,6 @@
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-right: 1px solid var(--grey-4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-logo {
|
.home-logo {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import { get } from "builderStore/api"
|
import { get } from "builderStore/api"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||||
|
import { Button } from "@budibase/bbui"
|
||||||
|
|
||||||
let promise = getApps()
|
let promise = getApps()
|
||||||
|
|
||||||
|
@ -43,21 +44,17 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="welcome">Welcome to Budibase</div>
|
<div class="header">
|
||||||
|
<div class="welcome">Welcome to the Budibase Beta</div>
|
||||||
|
<Button purple large on:click={showCreateAppModal}>Create New Web App</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<img src="/_builder/assets/rocket.jpg" alt="rocket" />
|
<img src="/_builder/assets/orange-landscape.png" alt="rocket" />
|
||||||
<div class="banner-content">
|
<div class="banner-content">
|
||||||
Every accomplishment starts with a decision to try.
|
Every accomplishment starts with a decision to try.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-section-header">
|
|
||||||
<div class="app-section-title">Your Web Apps</div>
|
|
||||||
<button class="banner-button" type="button" on:click={showCreateAppModal}>
|
|
||||||
<i class="ri-add-circle-fill" />
|
|
||||||
Create New Web App
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#await promise}
|
{#await promise}
|
||||||
<div class="spinner-container">
|
<div class="spinner-container">
|
||||||
|
@ -70,11 +67,17 @@
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin: 40px 80px 0px 80px;
|
||||||
|
}
|
||||||
|
|
||||||
.welcome {
|
.welcome {
|
||||||
font-size: 42px;
|
font-size: 42px;
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin: 40px 0px 0px 80px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner {
|
.banner {
|
||||||
|
@ -108,48 +111,4 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner-button {
|
|
||||||
background-color: var(--ink);
|
|
||||||
color: var(--white);
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: var(--ink) 1px solid;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 400;
|
|
||||||
box-sizing: border-box;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease 0s;
|
|
||||||
overflow: hidden;
|
|
||||||
outline: none;
|
|
||||||
user-select: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ri-add-circle-fill {
|
|
||||||
margin-right: 4px;
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner-button:hover {
|
|
||||||
background-color: var(--white);
|
|
||||||
color: var(--ink);
|
|
||||||
border: var(--grey-4) 1px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-section-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin: 40px 80px 0px 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-section-title {
|
|
||||||
font-size: 20px;
|
|
||||||
color: var(--ink);
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
BIN
packages/server/builder/assets/orange-landscape.png
Normal file
BIN
packages/server/builder/assets/orange-landscape.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 MiB |
|
@ -90,6 +90,22 @@ exports.create = async function(ctx) {
|
||||||
ctx.message = `Application ${ctx.request.body.name} created successfully`
|
ctx.message = `Application ${ctx.request.body.name} created successfully`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.update = async function(ctx) {
|
||||||
|
const clientId = await lookupClientId(ctx.params.applicationId)
|
||||||
|
const db = new CouchDB(ClientDb.name(clientId))
|
||||||
|
const application = await db.get(ctx.params.applicationId)
|
||||||
|
|
||||||
|
const data = ctx.request.body
|
||||||
|
const newData = { ...application, ...data }
|
||||||
|
|
||||||
|
const response = await db.put(newData)
|
||||||
|
data._rev = response.rev
|
||||||
|
|
||||||
|
ctx.status = 200
|
||||||
|
ctx.message = `Application ${application.name} updated successfully.`
|
||||||
|
ctx.body = response
|
||||||
|
}
|
||||||
|
|
||||||
const createEmptyAppPackage = async (ctx, app) => {
|
const createEmptyAppPackage = async (ctx, app) => {
|
||||||
const templateFolder = resolve(
|
const templateFolder = resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
|
|
|
@ -12,6 +12,7 @@ router
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
controller.fetchAppPackage
|
controller.fetchAppPackage
|
||||||
)
|
)
|
||||||
|
.put("/api/:applicationId", authorized(BUILDER), controller.update)
|
||||||
.post("/api/applications", authorized(BUILDER), controller.create)
|
.post("/api/applications", authorized(BUILDER), controller.create)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
Loading…
Reference in a new issue