Add resizable screen/component sections and remove redundant /components route
This commit is contained in:
parent
a83e987dcd
commit
a54c5b7222
|
@ -225,7 +225,7 @@ export const getFrontendStore = () => {
|
|||
// Select new screen
|
||||
store.update(state => {
|
||||
state.selectedScreenId = screen._id
|
||||
state.selectedComponentId = screen.props?._id
|
||||
state.selectedComponentId = "screen"
|
||||
return state
|
||||
})
|
||||
},
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<!-- Required to make Routify happy -->
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import Panel from "components/design/Panel.svelte"
|
||||
import { goto } from "@roxi/routify"
|
||||
import { goto, url } from "@roxi/routify"
|
||||
import { Layout, Search, Icon, Body, notifications } from "@budibase/bbui"
|
||||
import structure from "./componentStructure.json"
|
||||
import { store, selectedComponent, selectedScreen } from "builderStore"
|
|
@ -9,9 +9,7 @@
|
|||
<div class="app-panel">
|
||||
<div class="header">
|
||||
<div class="header-left">
|
||||
{#if $isActive("./screens") || $isActive("./components")}
|
||||
<UndoRedoControl store={screenHistoryStore} />
|
||||
{/if}
|
||||
<UndoRedoControl store={screenHistoryStore} />
|
||||
</div>
|
||||
<div class="header-right">
|
||||
{#if $store.clientFeatures.devicePreview}
|
||||
|
|
|
@ -70,9 +70,7 @@
|
|||
$: refreshContent(json)
|
||||
|
||||
// Determine if the add component menu is active
|
||||
$: isAddingComponent = $isActive(
|
||||
`./components/${$selectedComponent?._id}/new`
|
||||
)
|
||||
$: isAddingComponent = $isActive(`./${$selectedComponent?._id}/new`)
|
||||
|
||||
// Register handler to send custom to the preview
|
||||
$: sendPreviewEvent = (name, payload) => {
|
||||
|
@ -215,9 +213,9 @@
|
|||
|
||||
const toggleAddComponent = () => {
|
||||
if (isAddingComponent) {
|
||||
$goto(`./components/${$selectedComponent?._id}`)
|
||||
$goto(`./${$selectedComponent?._id}`)
|
||||
} else {
|
||||
$goto(`./components/${$selectedComponent?._id}/new`)
|
||||
$goto(`./${$selectedComponent?._id}/new`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
let scrolling = false
|
||||
|
||||
const toNewComponentRoute = () => {
|
||||
if ($isActive("./new")) {
|
||||
if ($isActive(`./${$store.selectedComponentId}/new`)) {
|
||||
return
|
||||
} else {
|
||||
$goto(`./new`)
|
||||
$goto(`./${$store.selectedComponentId}/new`)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,11 +31,7 @@
|
|||
}
|
||||
|
||||
const handleScroll = e => {
|
||||
if (e.target.scrollTop === 0) {
|
||||
scrolling = false
|
||||
} else {
|
||||
scrolling = true
|
||||
}
|
||||
scrolling = e.target.scrollTop !== 0
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
import ScreenList from "./ScreenList/index.svelte"
|
||||
import ComponentList from "./ComponentList/index.svelte"
|
||||
import { isActive } from "@roxi/routify"
|
||||
</script>
|
||||
|
||||
<div class="panel">
|
||||
<ScreenList />
|
||||
{#if $isActive("./:componentId")}
|
||||
<ComponentList />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.panel {
|
||||
width: 310px;
|
||||
height: 100%;
|
||||
border-right: var(--border-light);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
|
@ -9,29 +9,42 @@
|
|||
|
||||
let newScreen = false
|
||||
let search = false
|
||||
let resizing = false
|
||||
let searchValue = ""
|
||||
let searchInput
|
||||
let screensContainer
|
||||
let scrolling = false
|
||||
let height = "210px"
|
||||
let previousHeight = null
|
||||
let dragOffset
|
||||
|
||||
$: filteredScreens = getFilteredScreens($sortedScreens, searchValue)
|
||||
|
||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||
|
||||
const openSearch = async () => {
|
||||
search = true
|
||||
await tick()
|
||||
searchInput.focus()
|
||||
screensContainer.scroll({ top: 0, behavior: "smooth" })
|
||||
previousHeight = height
|
||||
height = "calc(100% + 1px)"
|
||||
}
|
||||
|
||||
const closeSearch = () => {
|
||||
const closeSearch = async () => {
|
||||
if (previousHeight) {
|
||||
// Restore previous height and wait for animation
|
||||
height = previousHeight
|
||||
previousHeight = null
|
||||
await sleep(300)
|
||||
}
|
||||
search = false
|
||||
searchValue = ""
|
||||
}
|
||||
|
||||
const getFilteredScreens = (screens, search) => {
|
||||
return screens.filter(screen => {
|
||||
const searchMatch = !search || screen.routing.route.includes(search)
|
||||
return searchMatch
|
||||
return !search || screen.routing.route.includes(search)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -54,17 +67,33 @@
|
|||
}
|
||||
|
||||
const handleScroll = e => {
|
||||
if (e.target.scrollTop === 0) {
|
||||
scrolling = false
|
||||
} else {
|
||||
scrolling = true
|
||||
scrolling = e.target.scrollTop !== 0
|
||||
}
|
||||
|
||||
const startResizing = e => {
|
||||
resizing = true
|
||||
dragOffset = parseInt(height) - e.clientY
|
||||
document.addEventListener("mousemove", resize)
|
||||
document.addEventListener("mouseup", stopResizing)
|
||||
}
|
||||
|
||||
const resize = e => {
|
||||
const newHeight = Math.max(0, e.clientY + dragOffset)
|
||||
if (newHeight == null || isNaN(newHeight)) {
|
||||
return
|
||||
}
|
||||
height = `${newHeight}px`
|
||||
}
|
||||
|
||||
const stopResizing = () => {
|
||||
resizing = false
|
||||
document.removeEventListener("mousemove", resize)
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
<div class="screens" class:screenSearch={search}>
|
||||
<div class="header" class:headerScrolling={scrolling}>
|
||||
<div class="screens" class:search class:resizing style={`height:${height};`}>
|
||||
<div class="header" class:scrolling>
|
||||
<input
|
||||
readonly={!search}
|
||||
bind:value={searchValue}
|
||||
|
@ -113,6 +142,8 @@
|
|||
</Layout>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="divider" on:mousedown={startResizing} />
|
||||
</div>
|
||||
|
||||
<div class="newScreen" class:newScreenVisible={newScreen}>
|
||||
|
@ -129,20 +160,24 @@
|
|||
z-index: 2;
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
.newScreenVisible {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.screens {
|
||||
height: 210px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: height 300ms ease-out;
|
||||
min-height: 147px;
|
||||
max-height: calc(100% - 147px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.screenSearch {
|
||||
height: 100%;
|
||||
.screens.search {
|
||||
transition: height 300ms ease-out;
|
||||
max-height: none;
|
||||
}
|
||||
.screens.resizing {
|
||||
user-select: none;
|
||||
cursor: row-resize;
|
||||
}
|
||||
|
||||
.header {
|
||||
|
@ -154,11 +189,10 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: border-bottom 300ms ease-out;
|
||||
transition: border-bottom 130ms ease-out;
|
||||
}
|
||||
|
||||
.headerScrolling {
|
||||
border-bottom: 2px solid var(--grey-2);
|
||||
.header.scrolling {
|
||||
border-bottom: var(--border-light);
|
||||
}
|
||||
|
||||
.input {
|
||||
|
@ -178,8 +212,7 @@
|
|||
.input::placeholder {
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
|
||||
.screenSearch input {
|
||||
.screens.search input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
@ -197,6 +230,9 @@
|
|||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.screens.resizing .content {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.screens :global(.nav-item) {
|
||||
padding-right: 8px !important;
|
||||
|
@ -208,7 +244,6 @@
|
|||
margin-right: 10px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.searchButton:hover {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
@ -223,15 +258,14 @@
|
|||
cursor: pointer;
|
||||
transition: transform 300ms ease-out;
|
||||
}
|
||||
.addButton:hover {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.addButton:hover {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
|
@ -240,4 +274,24 @@
|
|||
.no-results {
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
|
||||
.divider {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
transform: translateY(50%);
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
.divider:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: var(--spectrum-global-color-gray-200);
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.divider:hover {
|
||||
cursor: row-resize;
|
||||
}
|
||||
</style>
|
|
@ -4,7 +4,7 @@
|
|||
import { syncURLToState } from "helpers/urlStateSync"
|
||||
import { store } from "builderStore"
|
||||
import { onDestroy } from "svelte"
|
||||
import LeftPanel from "./components/[componentId]/_components/LeftPanel/index.svelte"
|
||||
import LeftPanel from "./_components/LeftPanel.svelte"
|
||||
|
||||
$: screenId = $store.selectedScreenId
|
||||
$: store.actions.websocket.selectResource(screenId)
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<script>
|
||||
import Screens from "./Screens/index.svelte"
|
||||
import Components from "./Components/index.svelte"
|
||||
import { selectedScreen } from "builderStore"
|
||||
</script>
|
||||
|
||||
<div class="panel">
|
||||
<Screens />
|
||||
<div class="divider" />
|
||||
{#if $selectedScreen}
|
||||
<Components />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.panel {
|
||||
width: 310px;
|
||||
height: 100%;
|
||||
border-right: var(--border-light);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
.divider {
|
||||
border-bottom: var(--border-light);
|
||||
}
|
||||
</style>
|
|
@ -1,4 +0,0 @@
|
|||
<!--
|
||||
Placeholder file so that routify works.
|
||||
No unique content is needed in this index page.
|
||||
-->
|
|
@ -1,8 +0,0 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { redirect } from "@roxi/routify"
|
||||
|
||||
onMount(() => {
|
||||
$redirect(`./screen`)
|
||||
})
|
||||
</script>
|
|
@ -1,8 +1,5 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { redirect } from "@roxi/routify"
|
||||
|
||||
onMount(() => {
|
||||
$redirect("./components/screen")
|
||||
})
|
||||
$redirect("./screen")
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
$: {
|
||||
if ($frontendStore.screens.length > 0) {
|
||||
$redirect(`./${$frontendStore.screens[0]._id}/components/screen`)
|
||||
$redirect(`./${$frontendStore.screens[0]._id}/screen`)
|
||||
} else {
|
||||
$redirect("./new")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue