Add support for correct mobile and tablet previews
This commit is contained in:
parent
e1d102c0c3
commit
4d06d682d8
|
@ -85,30 +85,45 @@
|
||||||
<UserBindingsProvider>
|
<UserBindingsProvider>
|
||||||
<DeviceBindingsProvider>
|
<DeviceBindingsProvider>
|
||||||
<StateBindingsProvider>
|
<StateBindingsProvider>
|
||||||
<CustomThemeWrapper>
|
<!-- Settings bar can be rendered outside of device preview -->
|
||||||
<div id="app-root" class:preview={$builderStore.inBuilder}>
|
|
||||||
{#key $screenStore.activeLayout._id}
|
|
||||||
<Component instance={$screenStore.activeLayout.props} />
|
|
||||||
{/key}
|
|
||||||
</div>
|
|
||||||
</CustomThemeWrapper>
|
|
||||||
<NotificationDisplay />
|
|
||||||
<ConfirmationDisplay />
|
|
||||||
<PeekScreenDisplay />
|
|
||||||
<!-- Key block needs to be outside the if statement or it breaks -->
|
<!-- Key block needs to be outside the if statement or it breaks -->
|
||||||
{#key $builderStore.selectedComponentId}
|
{#key $builderStore.selectedComponentId}
|
||||||
{#if $builderStore.inBuilder}
|
{#if $builderStore.inBuilder}
|
||||||
<SettingsBar />
|
<SettingsBar />
|
||||||
{/if}
|
{/if}
|
||||||
{/key}
|
{/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
|
We don't want to key these by componentID as they control their own
|
||||||
re-mounting to avoid flashes.
|
re-mounting to avoid flashes.
|
||||||
-->
|
-->
|
||||||
{#if $builderStore.inBuilder}
|
{#if $builderStore.inBuilder}
|
||||||
<SelectionIndicator />
|
<SelectionIndicator />
|
||||||
<HoverIndicator />
|
<HoverIndicator />
|
||||||
{/if}
|
{/if}
|
||||||
|
</div>
|
||||||
</StateBindingsProvider>
|
</StateBindingsProvider>
|
||||||
</DeviceBindingsProvider>
|
</DeviceBindingsProvider>
|
||||||
</UserBindingsProvider>
|
</UserBindingsProvider>
|
||||||
|
@ -117,20 +132,33 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#spectrum-root,
|
#spectrum-root {
|
||||||
#app-root {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
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 {
|
#app-root {
|
||||||
position: relative;
|
overflow: hidden;
|
||||||
}
|
height: 100%;
|
||||||
#app-root.preview {
|
width: 100%;
|
||||||
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -157,4 +185,21 @@
|
||||||
.error :global(h1) {
|
.error :global(h1) {
|
||||||
font-weight: 400;
|
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>
|
</style>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
const { routeStore, styleable, linkable, builderStore } = getContext("sdk")
|
const { routeStore, styleable, linkable, builderStore } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
const context = getContext("context")
|
||||||
|
|
||||||
export let title
|
export let title
|
||||||
export let hideTitle = false
|
export let hideTitle = false
|
||||||
|
@ -58,7 +59,12 @@
|
||||||
}
|
}
|
||||||
</script>
|
</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"}
|
{#if typeClass !== "none"}
|
||||||
<div class="nav-wrapper" class:sticky class:hidden={isPeeking}>
|
<div class="nav-wrapper" class:sticky class:hidden={isPeeking}>
|
||||||
<div class="nav nav--{typeClass} size--{widthClass}">
|
<div class="nav nav--{typeClass} size--{widthClass}">
|
||||||
|
@ -286,101 +292,97 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Desktop nav overrides */
|
/* Desktop nav overrides */
|
||||||
@media (min-width: 600px) {
|
.desktop.layout--left {
|
||||||
.layout--left {
|
flex-direction: row;
|
||||||
flex-direction: row;
|
overflow: hidden;
|
||||||
overflow: hidden;
|
}
|
||||||
}
|
.desktop.layout--left .main-wrapper {
|
||||||
.layout--left .main-wrapper {
|
height: 100%;
|
||||||
height: 100%;
|
overflow: auto;
|
||||||
overflow: auto;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.nav--left {
|
.desktop .nav--left {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
padding: var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav--left .links {
|
.desktop .nav--left .links {
|
||||||
margin-top: var(--spacing-m);
|
margin-top: var(--spacing-m);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
.nav--left .link {
|
.desktop .nav--left .link {
|
||||||
font-size: var(--spectrum-global-dimension-font-size-150);
|
font-size: var(--spectrum-global-dimension-font-size-150);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile nav overrides */
|
/* Mobile nav overrides */
|
||||||
@media (max-width: 600px) {
|
.mobile .nav-wrapper {
|
||||||
.nav-wrapper {
|
position: sticky;
|
||||||
position: sticky;
|
top: 0;
|
||||||
top: 0;
|
left: 0;
|
||||||
left: 0;
|
box-shadow: 0 0 8px -1px rgba(0, 0, 0, 0.075);
|
||||||
box-shadow: 0 0 8px -1px rgba(0, 0, 0, 0.075);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Show close button in drawer */
|
/* Show close button in drawer */
|
||||||
.close {
|
.mobile .close {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force standard top bar */
|
/* Force standard top bar */
|
||||||
.nav {
|
.mobile .nav {
|
||||||
padding: var(--spacing-m) 16px;
|
padding: var(--spacing-m) 16px;
|
||||||
}
|
}
|
||||||
.burger {
|
.mobile .burger {
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
}
|
}
|
||||||
.logo {
|
.mobile .logo {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
.logo :global(h1) {
|
.mobile .logo :global(h1) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reduce padding */
|
/* Reduce padding */
|
||||||
.main {
|
.mobile .main {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transform links into drawer */
|
/* Transform links into drawer */
|
||||||
.links {
|
.mobile .links {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: -250px;
|
left: -250px;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
width: 250px;
|
width: 250px;
|
||||||
transition: transform 0.26s ease-in-out, opacity 0.26s ease-in-out;
|
transition: transform 0.26s ease-in-out, opacity 0.26s ease-in-out;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
background: var(--navBackground);
|
background: var(--navBackground);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
padding: var(--spacing-xl);
|
padding: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
.link {
|
.mobile .link {
|
||||||
width: calc(100% - 30px);
|
width: calc(100% - 30px);
|
||||||
font-size: 120%;
|
font-size: 120%;
|
||||||
}
|
}
|
||||||
.links.visible {
|
.mobile .links.visible {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(250px);
|
transform: translateX(250px);
|
||||||
box-shadow: 0 0 80px 20px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 0 80px 20px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
.mobile-click-handler.visible {
|
.mobile .mobile-click-handler.visible {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 998;
|
z-index: 998;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const doc = document.documentElement
|
const doc = document.getElementById("device-root")
|
||||||
resizeObserver.observe(doc)
|
resizeObserver.observe(doc)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
|
@ -18,6 +18,7 @@ const loadBudibase = () => {
|
||||||
previewType: window["##BUDIBASE_PREVIEW_TYPE##"],
|
previewType: window["##BUDIBASE_PREVIEW_TYPE##"],
|
||||||
theme: window["##BUDIBASE_PREVIEW_THEME##"],
|
theme: window["##BUDIBASE_PREVIEW_THEME##"],
|
||||||
customTheme: window["##BUDIBASE_PREVIEW_CUSTOM_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
|
// Set app ID - this window flag is set by both the preview and the real
|
||||||
|
|
|
@ -20,6 +20,9 @@ const createBuilderStore = () => {
|
||||||
previewId: null,
|
previewId: null,
|
||||||
previewType: null,
|
previewType: null,
|
||||||
selectedPath: [],
|
selectedPath: [],
|
||||||
|
theme: null,
|
||||||
|
customTheme: null,
|
||||||
|
previewDevice: "desktop",
|
||||||
}
|
}
|
||||||
const writableStore = writable(initialState)
|
const writableStore = writable(initialState)
|
||||||
const derivedStore = derived(writableStore, $state => {
|
const derivedStore = derived(writableStore, $state => {
|
||||||
|
|
Loading…
Reference in New Issue