Add support for correct mobile and tablet previews

This commit is contained in:
Andrew Kingston 2021-09-08 09:40:25 +01:00
parent e1d102c0c3
commit 4d06d682d8
5 changed files with 163 additions and 112 deletions

View File

@ -85,30 +85,45 @@
<UserBindingsProvider>
<DeviceBindingsProvider>
<StateBindingsProvider>
<CustomThemeWrapper>
<div id="app-root" class:preview={$builderStore.inBuilder}>
{#key $screenStore.activeLayout._id}
<Component instance={$screenStore.activeLayout.props} />
{/key}
</div>
</CustomThemeWrapper>
<NotificationDisplay />
<ConfirmationDisplay />
<PeekScreenDisplay />
<!-- Settings bar can be rendered outside of device preview -->
<!-- Key block needs to be outside the if statement or it breaks -->
{#key $builderStore.selectedComponentId}
{#if $builderStore.inBuilder}
<SettingsBar />
{/if}
{/key}
<!--
<!-- Device boundary -->
<div
id="device-root"
class:preview={$builderStore.inBuilder}
class:tablet-preview={$builderStore.previewDevice === "tablet"}
class:mobile-preview={$builderStore.previewDevice === "mobile"}
>
<!-- Actual app -->
<div id="app-root">
<CustomThemeWrapper>
{#key $screenStore.activeLayout._id}
<Component instance={$screenStore.activeLayout.props} />
{/key}
<!-- Layers on top of app -->
<NotificationDisplay />
<ConfirmationDisplay />
<PeekScreenDisplay />
</CustomThemeWrapper>
</div>
<!-- Selection indicators should be bounded by device -->
<!--
We don't want to key these by componentID as they control their own
re-mounting to avoid flashes.
-->
{#if $builderStore.inBuilder}
<SelectionIndicator />
<HoverIndicator />
{/if}
{#if $builderStore.inBuilder}
<SelectionIndicator />
<HoverIndicator />
{/if}
</div>
</StateBindingsProvider>
</DeviceBindingsProvider>
</UserBindingsProvider>
@ -117,20 +132,33 @@
{/if}
<style>
#spectrum-root,
#app-root {
height: 100%;
width: 100%;
#spectrum-root {
padding: 0;
margin: 0;
overflow: hidden;
height: 100%;
width: 100%;
background: transparent;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
#device-root {
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
background-color: transparent;
}
#app-root {
position: relative;
}
#app-root.preview {
border: 1px solid var(--spectrum-global-color-gray-300);
overflow: hidden;
height: 100%;
width: 100%;
}
.error {
position: absolute;
width: 100%;
@ -157,4 +185,21 @@
.error :global(h1) {
font-weight: 400;
}
/* Preview styles */
#device-root.preview {
padding: 2px;
}
#device-root.tablet-preview {
width: calc(1024px + 8px);
height: calc(768px + 8px);
}
#device-root.mobile-preview {
width: calc(390px + 8px);
height: calc(844px + 8px);
}
.preview #app-root {
border: 2px solid var(--spectrum-global-color-gray-300);
border-radius: 4px;
}
</style>

View File

@ -5,6 +5,7 @@
const { routeStore, styleable, linkable, builderStore } = getContext("sdk")
const component = getContext("component")
const context = getContext("context")
export let title
export let hideTitle = false
@ -58,7 +59,12 @@
}
</script>
<div class="layout layout--{typeClass}" use:styleable={$component.styles}>
<div
class="layout layout--{typeClass}"
use:styleable={$component.styles}
class:desktop={!$context.device.mobile && !$context.device.tablet}
class:mobile={!!$context.device.mobile}
>
{#if typeClass !== "none"}
<div class="nav-wrapper" class:sticky class:hidden={isPeeking}>
<div class="nav nav--{typeClass} size--{widthClass}">
@ -286,101 +292,97 @@
}
/* Desktop nav overrides */
@media (min-width: 600px) {
.layout--left {
flex-direction: row;
overflow: hidden;
}
.layout--left .main-wrapper {
height: 100%;
overflow: auto;
}
.desktop.layout--left {
flex-direction: row;
overflow: hidden;
}
.desktop.layout--left .main-wrapper {
height: 100%;
overflow: auto;
}
.nav--left {
width: 250px;
padding: var(--spacing-xl);
}
.desktop .nav--left {
width: 250px;
padding: var(--spacing-xl);
}
.nav--left .links {
margin-top: var(--spacing-m);
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
.nav--left .link {
font-size: var(--spectrum-global-dimension-font-size-150);
}
.desktop .nav--left .links {
margin-top: var(--spacing-m);
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
.desktop .nav--left .link {
font-size: var(--spectrum-global-dimension-font-size-150);
}
/* Mobile nav overrides */
@media (max-width: 600px) {
.nav-wrapper {
position: sticky;
top: 0;
left: 0;
box-shadow: 0 0 8px -1px rgba(0, 0, 0, 0.075);
}
.mobile .nav-wrapper {
position: sticky;
top: 0;
left: 0;
box-shadow: 0 0 8px -1px rgba(0, 0, 0, 0.075);
}
/* Show close button in drawer */
.close {
display: block;
}
/* Show close button in drawer */
.mobile .close {
display: block;
}
/* Force standard top bar */
.nav {
padding: var(--spacing-m) 16px;
}
.burger {
display: grid;
place-items: center;
}
.logo {
flex: 0 0 auto;
}
.logo :global(h1) {
display: none;
}
/* Force standard top bar */
.mobile .nav {
padding: var(--spacing-m) 16px;
}
.mobile .burger {
display: grid;
place-items: center;
}
.mobile .logo {
flex: 0 0 auto;
}
.mobile .logo :global(h1) {
display: none;
}
/* Reduce padding */
.main {
padding: 16px;
}
/* Reduce padding */
.mobile .main {
padding: 16px;
}
/* Transform links into drawer */
.links {
margin-top: 0;
position: fixed;
top: 0;
left: -250px;
transform: translateX(0);
width: 250px;
transition: transform 0.26s ease-in-out, opacity 0.26s ease-in-out;
height: 100vh;
opacity: 0;
background: var(--navBackground);
z-index: 999;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
padding: var(--spacing-xl);
}
.link {
width: calc(100% - 30px);
font-size: 120%;
}
.links.visible {
opacity: 1;
transform: translateX(250px);
box-shadow: 0 0 80px 20px rgba(0, 0, 0, 0.3);
}
.mobile-click-handler.visible {
position: fixed;
display: block;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 998;
}
/* Transform links into drawer */
.mobile .links {
margin-top: 0;
position: absolute;
top: 0;
left: -250px;
transform: translateX(0);
width: 250px;
transition: transform 0.26s ease-in-out, opacity 0.26s ease-in-out;
height: 100vh;
opacity: 0;
background: var(--navBackground);
z-index: 999;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
padding: var(--spacing-xl);
}
.mobile .link {
width: calc(100% - 30px);
font-size: 120%;
}
.mobile .links.visible {
opacity: 1;
transform: translateX(250px);
box-shadow: 0 0 80px 20px rgba(0, 0, 0, 0.3);
}
.mobile .mobile-click-handler.visible {
position: absolute;
display: block;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 998;
}
</style>

View File

@ -17,7 +17,7 @@
}
onMount(() => {
const doc = document.documentElement
const doc = document.getElementById("device-root")
resizeObserver.observe(doc)
return () => {

View File

@ -18,6 +18,7 @@ const loadBudibase = () => {
previewType: window["##BUDIBASE_PREVIEW_TYPE##"],
theme: window["##BUDIBASE_PREVIEW_THEME##"],
customTheme: window["##BUDIBASE_PREVIEW_CUSTOM_THEME##"],
previewDevice: window["##BUDIBASE_PREVIEW_DEVICE##"],
})
// Set app ID - this window flag is set by both the preview and the real

View File

@ -20,6 +20,9 @@ const createBuilderStore = () => {
previewId: null,
previewType: null,
selectedPath: [],
theme: null,
customTheme: null,
previewDevice: "desktop",
}
const writableStore = writable(initialState)
const derivedStore = derived(writableStore, $state => {