Refactor routes and start updating core design UI into new components
This commit is contained in:
parent
4126e5884d
commit
c35906a831
|
@ -17,10 +17,13 @@
|
||||||
export let negative = false
|
export let negative = false
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
export let active = false
|
export let active = false
|
||||||
|
export let color = null
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="spectrum-StatusLight spectrum-StatusLight--size{size}"
|
class="spectrum-StatusLight spectrum-StatusLight--size{size}"
|
||||||
|
class:custom={!!color}
|
||||||
|
style={`--color: ${color};`}
|
||||||
class:spectrum-StatusLight--celery={celery}
|
class:spectrum-StatusLight--celery={celery}
|
||||||
class:spectrum-StatusLight--yellow={yellow}
|
class:spectrum-StatusLight--yellow={yellow}
|
||||||
class:spectrum-StatusLight--fuchsia={fuchsia}
|
class:spectrum-StatusLight--fuchsia={fuchsia}
|
||||||
|
@ -39,3 +42,13 @@
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectrum-StatusLight {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
.custom::before {
|
||||||
|
background: var(--color) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
tables,
|
tables,
|
||||||
} from "stores/backend"
|
} from "stores/backend"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { DesignTabs, FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
import {
|
import {
|
||||||
findComponentType,
|
findComponentType,
|
||||||
|
@ -48,8 +48,6 @@ const INITIAL_FRONTEND_STATE = {
|
||||||
continueIfAction: false,
|
continueIfAction: false,
|
||||||
},
|
},
|
||||||
currentFrontEndType: "none",
|
currentFrontEndType: "none",
|
||||||
selectedDesignTab: DesignTabs.SCREENS,
|
|
||||||
selectedScreenId: "",
|
|
||||||
selectedLayoutId: "",
|
selectedLayoutId: "",
|
||||||
selectedComponentId: "",
|
selectedComponentId: "",
|
||||||
errors: [],
|
errors: [],
|
||||||
|
@ -61,6 +59,9 @@ const INITIAL_FRONTEND_STATE = {
|
||||||
theme: "",
|
theme: "",
|
||||||
customTheme: {},
|
customTheme: {},
|
||||||
previewDevice: "desktop",
|
previewDevice: "desktop",
|
||||||
|
|
||||||
|
// URL params
|
||||||
|
selectedScreenId: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFrontendStore = () => {
|
export const getFrontendStore = () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Icon } from "@budibase/bbui"
|
import { Icon, StatusLight } from "@budibase/bbui"
|
||||||
import { createEventDispatcher, getContext } from "svelte"
|
import { createEventDispatcher, getContext } from "svelte"
|
||||||
|
|
||||||
export let icon
|
export let icon
|
||||||
|
@ -13,6 +13,8 @@
|
||||||
export let draggable = false
|
export let draggable = false
|
||||||
export let iconText
|
export let iconText
|
||||||
export let iconColor
|
export let iconColor
|
||||||
|
export let scrollable = false
|
||||||
|
export let color
|
||||||
|
|
||||||
const scrollApi = getContext("scroll")
|
const scrollApi = getContext("scroll")
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
@ -43,7 +45,7 @@
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
class:border
|
class:border
|
||||||
class:selected
|
class:selected
|
||||||
style={`padding-left: ${20 + indentLevel * 14}px`}
|
style={`padding-left: ${14 + indentLevel * 14}px`}
|
||||||
{draggable}
|
{draggable}
|
||||||
on:dragend
|
on:dragend
|
||||||
on:dragstart
|
on:dragstart
|
||||||
|
@ -52,6 +54,7 @@
|
||||||
on:click={onClick}
|
on:click={onClick}
|
||||||
ondragover="return false"
|
ondragover="return false"
|
||||||
ondragenter="return false"
|
ondragenter="return false"
|
||||||
|
class:scrollable
|
||||||
>
|
>
|
||||||
<div class="nav-item-content" bind:this={contentRef}>
|
<div class="nav-item-content" bind:this={contentRef}>
|
||||||
{#if withArrow}
|
{#if withArrow}
|
||||||
|
@ -76,6 +79,9 @@
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if color}
|
||||||
|
<StatusLight size="L" {color} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -85,9 +91,14 @@
|
||||||
color: var(--grey-7);
|
color: var(--grey-7);
|
||||||
transition: background-color
|
transition: background-color
|
||||||
var(--spectrum-global-animation-duration-100, 130ms) ease-in-out;
|
var(--spectrum-global-animation-duration-100, 130ms) ease-in-out;
|
||||||
padding: 0 var(--spacing-m) 0 var(--spacing-xl);
|
padding: 0 var(--spacing-m) 0 var(--spacing-l);
|
||||||
height: 32px;
|
height: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.nav-item.scrollable {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
@ -136,10 +147,13 @@
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: var(--spectrum-global-dimension-font-size-75);
|
font-size: var(--spectrum-global-dimension-font-size-75);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
max-width: 160px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
.scrollable .text {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
max-width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<script>
|
||||||
|
import ComponentSelectionList from "./ComponentSelectionList.svelte"
|
||||||
|
import DevicePreviewSelect from "./DevicePreviewSelect.svelte"
|
||||||
|
import ThemeEditor from "./ThemeEditor.svelte"
|
||||||
|
import AppThemeSelect from "./AppThemeSelect.svelte"
|
||||||
|
import AppPreview from "./AppPreview.svelte"
|
||||||
|
import { store } from "builderStore"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="app-panel">
|
||||||
|
<div class="header">
|
||||||
|
<ComponentSelectionList />
|
||||||
|
{#if $store.clientFeatures.devicePreview}
|
||||||
|
<DevicePreviewSelect />
|
||||||
|
{/if}
|
||||||
|
{#if $store.clientFeatures.customThemes}
|
||||||
|
<ThemeEditor />
|
||||||
|
{:else if $store.clientFeatures.spectrumThemes}
|
||||||
|
<AppThemeSelect />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
{#key $store.version}
|
||||||
|
<AppPreview />
|
||||||
|
{/key}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.app-panel {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: var(--spacing-m);
|
||||||
|
padding: var(--spacing-l) 24px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-left: -6px;
|
||||||
|
}
|
||||||
|
.header > :global(*) {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
.header > :global(*:first-child) {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { onMount, onDestroy } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAsset, allScreens } from "builderStore"
|
||||||
import iframeTemplate from "./iframeTemplate"
|
import iframeTemplate from "./iframeTemplate"
|
||||||
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
|
@ -49,13 +49,8 @@
|
||||||
|
|
||||||
// Extract data to pass to the iframe
|
// Extract data to pass to the iframe
|
||||||
$: {
|
$: {
|
||||||
if ($store.currentFrontEndType === FrontendTypes.LAYOUT) {
|
screen = $allScreens.find(x => x._id === $store.selectedScreenId)
|
||||||
layout = $currentAsset
|
layout = $store.layouts.find(layout => layout._id === screen?.layoutId)
|
||||||
screen = screenPlaceholder
|
|
||||||
} else {
|
|
||||||
screen = $currentAsset
|
|
||||||
layout = $store.layouts.find(layout => layout._id === screen?.layoutId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$: selectedComponentId = $store.selectedComponentId ?? ""
|
$: selectedComponentId = $store.selectedComponentId ?? ""
|
||||||
$: previewData = {
|
$: previewData = {
|
||||||
|
@ -68,7 +63,7 @@
|
||||||
customTheme: $store.customTheme,
|
customTheme: $store.customTheme,
|
||||||
previewDevice: $store.previewDevice,
|
previewDevice: $store.previewDevice,
|
||||||
messagePassing: $store.clientFeatures.messagePassing,
|
messagePassing: $store.clientFeatures.messagePassing,
|
||||||
isBudibaseEvent: true
|
isBudibaseEvent: true,
|
||||||
}
|
}
|
||||||
$: json = JSON.stringify(previewData)
|
$: json = JSON.stringify(previewData)
|
||||||
|
|
|
@ -141,9 +141,6 @@
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.container {
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
.setting {
|
.setting {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
|
@ -1 +0,0 @@
|
||||||
export { default } from "./CurrentItemPreview.svelte"
|
|
|
@ -7,9 +7,7 @@
|
||||||
} from "builderStore"
|
} from "builderStore"
|
||||||
import instantiateStore from "./dragDropStore"
|
import instantiateStore from "./dragDropStore"
|
||||||
import ComponentTree from "./ComponentTree.svelte"
|
import ComponentTree from "./ComponentTree.svelte"
|
||||||
import NavItem from "components/common/NavItem.svelte"
|
|
||||||
import PathDropdownMenu from "./PathDropdownMenu.svelte"
|
import PathDropdownMenu from "./PathDropdownMenu.svelte"
|
||||||
import ScreenDropdownMenu from "./ScreenDropdownMenu.svelte"
|
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
|
|
||||||
const ROUTE_NAME_MAP = {
|
const ROUTE_NAME_MAP = {
|
||||||
|
@ -32,7 +30,6 @@
|
||||||
|
|
||||||
$: selectedScreen = $currentAsset
|
$: selectedScreen = $currentAsset
|
||||||
$: allScreens = getAllScreens(route)
|
$: allScreens = getAllScreens(route)
|
||||||
$: filteredScreens = getFilteredScreens(allScreens, $screenSearchString)
|
|
||||||
$: hasSearchMatch = $screenSearchString && filteredScreens.length > 0
|
$: hasSearchMatch = $screenSearchString && filteredScreens.length > 0
|
||||||
$: noSearchMatch = $screenSearchString && !filteredScreens.length
|
$: noSearchMatch = $screenSearchString && !filteredScreens.length
|
||||||
$: routeSelected =
|
$: routeSelected =
|
||||||
|
@ -43,22 +40,6 @@
|
||||||
store.actions.screens.select(screenId)
|
store.actions.screens.select(screenId)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAllScreens = route => {
|
|
||||||
let screens = []
|
|
||||||
Object.entries(route.subpaths).forEach(([route, subpath]) => {
|
|
||||||
Object.entries(subpath.screens).forEach(([role, id]) => {
|
|
||||||
screens.push({ id, route, role })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return screens
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFilteredScreens = (screens, searchString) => {
|
|
||||||
return screens.filter(
|
|
||||||
screen => !searchString || screen.route.includes(searchString)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleManuallyOpened = () => {
|
const toggleManuallyOpened = () => {
|
||||||
if (get(screenSearchString)) {
|
if (get(screenSearchString)) {
|
||||||
return
|
return
|
||||||
|
@ -79,28 +60,5 @@
|
||||||
<PathDropdownMenu screens={allScreens} {path} />
|
<PathDropdownMenu screens={allScreens} {path} />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
|
|
||||||
{#if routeOpened}
|
{#if routeOpened}{/if}
|
||||||
{#each filteredScreens as screen (screen.id)}
|
|
||||||
<NavItem
|
|
||||||
icon="WebPage"
|
|
||||||
indentLevel={indent || 1}
|
|
||||||
selected={$store.selectedScreenId === screen.id &&
|
|
||||||
$store.currentView === "detail"}
|
|
||||||
opened={$store.selectedScreenId === screen.id}
|
|
||||||
text={ROUTE_NAME_MAP[screen.route]?.[screen.role] || screen.route}
|
|
||||||
withArrow={route.subpaths}
|
|
||||||
on:click={() => changeScreen(screen.id)}
|
|
||||||
>
|
|
||||||
<ScreenDropdownMenu screenId={screen.id} />
|
|
||||||
</NavItem>
|
|
||||||
{#if selectedScreen?._id === screen.id}
|
|
||||||
<ComponentTree
|
|
||||||
level={1}
|
|
||||||
components={selectedScreen.props._children}
|
|
||||||
currentComponent={$selectedComponent}
|
|
||||||
{dragDropStore}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -131,21 +131,7 @@
|
||||||
<Tabs {selected} on:select={navigate}>
|
<Tabs {selected} on:select={navigate}>
|
||||||
<Tab title="Screens">
|
<Tab title="Screens">
|
||||||
<div class="tab-content-padding">
|
<div class="tab-content-padding">
|
||||||
<BBUILayout noPadding gap="XS">
|
<BBUILayout noPadding gap="XS" />
|
||||||
<Select
|
|
||||||
on:change={updateAccessRole}
|
|
||||||
value={$selectedAccessRole}
|
|
||||||
label="Filter by Access"
|
|
||||||
getOptionLabel={role => role.name}
|
|
||||||
getOptionValue={role => role._id}
|
|
||||||
options={$roles}
|
|
||||||
/>
|
|
||||||
<Search
|
|
||||||
placeholder="Enter a route to search"
|
|
||||||
label="Search Screens"
|
|
||||||
bind:value={$screenSearchString}
|
|
||||||
/>
|
|
||||||
</BBUILayout>
|
|
||||||
<div class="nav-items-container" bind:this={scrollRef}>
|
<div class="nav-items-container" bind:this={scrollRef}>
|
||||||
<ComponentNavigationTree />
|
<ComponentNavigationTree />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<script>
|
||||||
|
import { Icon, Heading } from "@budibase/bbui"
|
||||||
|
|
||||||
|
export let title
|
||||||
|
export let showAddButton
|
||||||
|
export let onClickAddButton
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="navigation-panel">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
<Heading size="XS">{title || ""}</Heading>
|
||||||
|
</div>
|
||||||
|
{#if showAddButton}
|
||||||
|
<div class="add-button">
|
||||||
|
<Icon name="Add" on:click={onClickAddButton} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.navigation-panel {
|
||||||
|
width: 260px;
|
||||||
|
background: var(--background);
|
||||||
|
border-right: var(--border-light);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--spacing-m) var(--spacing-l);
|
||||||
|
border-bottom: var(--border-light);
|
||||||
|
gap: var(--spacing-l);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
.title :global(h1) {
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: 600;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.add-button {
|
||||||
|
flex: 0 0 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--spectrum-semantic-cta-color-background-default);
|
||||||
|
transition: background var(--spectrum-global-animation-duration-100, 130ms)
|
||||||
|
ease-out;
|
||||||
|
}
|
||||||
|
.add-button:hover {
|
||||||
|
background: var(--spectrum-semantic-cta-color-background-hover);
|
||||||
|
}
|
||||||
|
.add-button :global(svg) {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,13 +1,14 @@
|
||||||
|
import { Roles } from "./backend"
|
||||||
|
|
||||||
export const TableNames = {
|
export const TableNames = {
|
||||||
USERS: "ta_users",
|
USERS: "ta_users",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DesignTabs = {
|
export const RoleColours = {
|
||||||
SCREENS: "screens",
|
[Roles.ADMIN]: "var(--spectrum-global-color-static-seafoam-400)",
|
||||||
COMPONENTS: "components",
|
[Roles.POWER]: "var(--spectrum-global-color-static-purple-400)",
|
||||||
THEME: "theme",
|
[Roles.BASIC]: "var(--spectrum-global-color-static-magenta-400)",
|
||||||
NAVIGATION: "navigation",
|
[Roles.PUBLIC]: "var(--spectrum-global-color-static-yellow-400)",
|
||||||
LAYOUTS: "layouts",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FrontendTypes = {
|
export const FrontendTypes = {
|
||||||
|
|
|
@ -55,7 +55,7 @@ export const syncURLToState = options => {
|
||||||
// Updates the URL with new state values
|
// Updates the URL with new state values
|
||||||
const mapStateToUrl = state => {
|
const mapStateToUrl = state => {
|
||||||
// Determine new URL while checking for changes
|
// Determine new URL while checking for changes
|
||||||
let url = "."
|
let url = ".."
|
||||||
let needsUpdate = false
|
let needsUpdate = false
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
const urlValue = cachedParams?.[key.url]
|
const urlValue = cachedParams?.[key.url]
|
||||||
|
|
|
@ -1,23 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { IconSideNav, IconSideNavItem } from "@budibase/bbui"
|
import { IconSideNav, IconSideNavItem } from "@budibase/bbui"
|
||||||
import { params, goto } from "@roxi/routify"
|
import { params, goto, isActive } from "@roxi/routify"
|
||||||
import { DesignTabs } from "constants"
|
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { syncURLToState } from "helpers/urlStateSync"
|
import { syncURLToState } from "helpers/urlStateSync"
|
||||||
import { onDestroy } from "svelte"
|
import { onDestroy } from "svelte"
|
||||||
|
|
||||||
const updateTab = tab => {
|
|
||||||
store.update(state => {
|
|
||||||
state.selectedDesignTab = tab
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsync = syncURLToState({
|
const unsync = syncURLToState({
|
||||||
keys: [
|
keys: [
|
||||||
{
|
{
|
||||||
url: "tab",
|
url: "screenId",
|
||||||
state: "selectedDesignTab",
|
state: "selectedScreenId",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
store,
|
store,
|
||||||
|
@ -30,37 +22,37 @@
|
||||||
|
|
||||||
<!-- routify:options index=1 -->
|
<!-- routify:options index=1 -->
|
||||||
<div class="design">
|
<div class="design">
|
||||||
<div class="side-nav">
|
<div class="icon-nav">
|
||||||
<IconSideNav>
|
<IconSideNav>
|
||||||
<IconSideNavItem
|
<IconSideNavItem
|
||||||
icon="WebPage"
|
icon="WebPage"
|
||||||
tooltip="Screens"
|
tooltip="Screens"
|
||||||
active={$store.selectedDesignTab === DesignTabs.SCREENS}
|
active={$isActive("./screens")}
|
||||||
on:click={() => updateTab(DesignTabs.SCREENS)}
|
on:click={() => $goto("./screens")}
|
||||||
/>
|
/>
|
||||||
<IconSideNavItem
|
<IconSideNavItem
|
||||||
icon="ViewList"
|
icon="ViewList"
|
||||||
tooltip="Components"
|
tooltip="Components"
|
||||||
active={$store.selectedDesignTab === DesignTabs.COMPONENTS}
|
active={$isActive("./components")}
|
||||||
on:click={() => updateTab(DesignTabs.COMPONENTS)}
|
on:click={() => $goto("./components")}
|
||||||
/>
|
/>
|
||||||
<IconSideNavItem
|
<IconSideNavItem
|
||||||
icon="Brush"
|
icon="Brush"
|
||||||
tooltip="Theme"
|
tooltip="Theme"
|
||||||
active={$store.selectedDesignTab === DesignTabs.THEME}
|
active={$isActive("./theme")}
|
||||||
on:click={() => updateTab(DesignTabs.THEME)}
|
on:click={() => $goto("./theme")}
|
||||||
/>
|
/>
|
||||||
<IconSideNavItem
|
<IconSideNavItem
|
||||||
icon="Link"
|
icon="Link"
|
||||||
tooltip="Navigation"
|
tooltip="Navigation"
|
||||||
active={$store.selectedDesignTab === DesignTabs.NAVIGATION}
|
active={$isActive("./navigation")}
|
||||||
on:click={() => updateTab(DesignTabs.NAVIGATION)}
|
on:click={() => $goto("./navigation")}
|
||||||
/>
|
/>
|
||||||
<IconSideNavItem
|
<IconSideNavItem
|
||||||
icon="Experience"
|
icon="Experience"
|
||||||
tooltip="Layouts"
|
tooltip="Layouts"
|
||||||
active={$store.selectedDesignTab === DesignTabs.LAYOUTS}
|
active={$isActive("./layouts")}
|
||||||
on:click={() => updateTab(DesignTabs.LAYOUTS)}
|
on:click={() => $goto("./layouts")}
|
||||||
/>
|
/>
|
||||||
</IconSideNav>
|
</IconSideNav>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,12 +69,14 @@
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
.side-nav {
|
.icon-nav {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
border-right: var(--border-light);
|
border-right: var(--border-light);
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -0,0 +1 @@
|
||||||
|
Components
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
|
$redirect(`./screens`)
|
||||||
|
</script>
|
|
@ -0,0 +1 @@
|
||||||
|
Layouts
|
|
@ -0,0 +1 @@
|
||||||
|
Navigation
|
|
@ -10,7 +10,7 @@
|
||||||
Helpers,
|
Helpers,
|
||||||
notifications,
|
notifications,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import ScreenDetailsModal from "../ScreenDetailsModal.svelte"
|
import ScreenDetailsModal from "./ScreenDetailsModal.svelte"
|
||||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
import { makeComponentUnique } from "builderStore/componentUtils"
|
import { makeComponentUnique } from "builderStore/componentUtils"
|
|
@ -0,0 +1 @@
|
||||||
|
<slot />
|
|
@ -156,24 +156,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="preview-pane">
|
<div class="preview-pane">
|
||||||
{#if $currentAsset}
|
{#if $currentAsset}{:else}
|
||||||
<div class="preview-header">
|
|
||||||
<ComponentSelectionList />
|
|
||||||
{#if $store.clientFeatures.devicePreview}
|
|
||||||
<DevicePreviewSelect />
|
|
||||||
{/if}
|
|
||||||
{#if $store.clientFeatures.customThemes}
|
|
||||||
<ThemeEditor />
|
|
||||||
{:else if $store.clientFeatures.spectrumThemes}
|
|
||||||
<AppThemeSelect />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div class="preview-content">
|
|
||||||
{#key $store.version}
|
|
||||||
<CurrentItemPreview />
|
|
||||||
{/key}
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<div class="centered">
|
<div class="centered">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<Layout gap="S" justifyItems="center">
|
<Layout gap="S" justifyItems="center">
|
||||||
|
@ -247,34 +230,6 @@
|
||||||
border-right: var(--border-light);
|
border-right: var(--border-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-pane {
|
|
||||||
grid-column: 2;
|
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: stretch;
|
|
||||||
gap: var(--spacing-m);
|
|
||||||
padding: var(--spacing-xl) 40px;
|
|
||||||
}
|
|
||||||
.preview-header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
.preview-header > :global(*) {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.preview-header > :global(*:first-child) {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-content {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-pane {
|
.components-pane {
|
||||||
grid-column: 3;
|
grid-column: 3;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
|
@ -0,0 +1,69 @@
|
||||||
|
<script>
|
||||||
|
import { Search, Layout, Select } from "@budibase/bbui"
|
||||||
|
import NavigationPanel from "components/design/NavigationPanel/NavigationPanel.svelte"
|
||||||
|
import { roles } from "stores/backend"
|
||||||
|
import { store, allScreens } from "builderStore"
|
||||||
|
import NavItem from "components/common/NavItem.svelte"
|
||||||
|
import ScreenDropdownMenu from "./_components/ScreenDropdownMenu.svelte"
|
||||||
|
import AppPanel from "components/design/AppPanel/AppPanel.svelte"
|
||||||
|
import { RoleColours } from "constants"
|
||||||
|
|
||||||
|
let searchString
|
||||||
|
let accessRole
|
||||||
|
|
||||||
|
$: filteredScreens = getFilteredScreens($allScreens, searchString)
|
||||||
|
|
||||||
|
const getFilteredScreens = (screens, searchString) => {
|
||||||
|
return screens
|
||||||
|
.filter(
|
||||||
|
screen => !searchString || screen.routing.route.includes(searchString)
|
||||||
|
)
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => {
|
||||||
|
return a.routing.route < b.routing.route ? -1 : 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRoleColor = roleId => {
|
||||||
|
return RoleColours[roleId] || "pink"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<NavigationPanel title="Screens" showAddButton onClickAddButton>
|
||||||
|
<Layout paddingX="L" paddingY="XL" gap="S">
|
||||||
|
<Search
|
||||||
|
placeholder="Enter a route to search"
|
||||||
|
value={searchString}
|
||||||
|
on:change={e => (searchString = e.detail)}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
bind:value={accessRole}
|
||||||
|
placeholder="All screens"
|
||||||
|
getOptionLabel={role => role.name}
|
||||||
|
getOptionValue={role => role._id}
|
||||||
|
options={$roles}
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
|
{#each filteredScreens as screen (screen._id)}
|
||||||
|
<NavItem
|
||||||
|
icon={screen.routing.route === "/" ? "Home" : "WebPage"}
|
||||||
|
indentLevel={0}
|
||||||
|
selected={$store.selectedScreenId === screen._id}
|
||||||
|
text={screen.routing.route}
|
||||||
|
on:click={() => ($store.selectedScreenId = screen._id)}
|
||||||
|
color={getRoleColor(screen.routing.roleId)}
|
||||||
|
>
|
||||||
|
<ScreenDropdownMenu screenId={screen._id} />
|
||||||
|
</NavItem>
|
||||||
|
<!--{#if selectedScreen?._id === screen.id}-->
|
||||||
|
<!-- <ComponentTree-->
|
||||||
|
<!-- level={1}-->
|
||||||
|
<!-- components={selectedScreen.props._children}-->
|
||||||
|
<!-- currentComponent={$selectedComponent}-->
|
||||||
|
<!-- {dragDropStore}-->
|
||||||
|
<!-- />-->
|
||||||
|
<!--{/if}-->
|
||||||
|
{/each}
|
||||||
|
</NavigationPanel>
|
||||||
|
|
||||||
|
<AppPanel />
|
|
@ -0,0 +1 @@
|
||||||
|
Theme
|
|
@ -1,2 +0,0 @@
|
||||||
<!-- routify:options index=1 -->
|
|
||||||
<slot />
|
|
|
@ -1,6 +0,0 @@
|
||||||
<script>
|
|
||||||
import { goto } from "@roxi/routify"
|
|
||||||
import { FrontendTypes } from "constants"
|
|
||||||
|
|
||||||
$goto(`./${FrontendTypes.SCREEN}`)
|
|
||||||
</script>
|
|
|
@ -1,6 +1,19 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@roxi/routify"
|
import { allScreens } from "builderStore"
|
||||||
import { DesignTabs } from "constants"
|
import { onMount } from "svelte"
|
||||||
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
$goto(`./${DesignTabs.SCREENS}`)
|
let loaded = false
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if ($allScreens?.length) {
|
||||||
|
$redirect(`./${$allScreens[0]._id}`)
|
||||||
|
} else {
|
||||||
|
loaded = true
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if loaded}
|
||||||
|
You need to create a screen!
|
||||||
|
{/if}
|
||||||
|
|
|
@ -276,7 +276,7 @@
|
||||||
|
|
||||||
.preview #app-root {
|
.preview #app-root {
|
||||||
border: 1px solid var(--spectrum-global-color-gray-300);
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
border-radius: 4px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print styles */
|
/* Print styles */
|
||||||
|
|
Loading…
Reference in New Issue