Add full navigation settings panel in new design UI. Remove navigation theme settings from theme panel
This commit is contained in:
parent
071dc5be4b
commit
3ada9a12c5
|
@ -56,3 +56,11 @@ export const BUDIBASE_INTERNAL_DB = "bb_internal"
|
||||||
export const APP_NAME_REGEX = /^[\w\s]+$/
|
export const APP_NAME_REGEX = /^[\w\s]+$/
|
||||||
// zero or more non-whitespace characters
|
// zero or more non-whitespace characters
|
||||||
export const APP_URL_REGEX = /^\S*$/
|
export const APP_URL_REGEX = /^\S*$/
|
||||||
|
|
||||||
|
export const DefaultAppTheme = {
|
||||||
|
primaryColor: "var(--spectrum-global-color-blue-600)",
|
||||||
|
primaryColorHover: "var(--spectrum-global-color-blue-500)",
|
||||||
|
buttonBorderRadius: "16px",
|
||||||
|
navBackground: "var(--spectrum-global-color-gray-50)",
|
||||||
|
navTextColor: "var(--spectrum-global-color-gray-800)",
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ export const syncURLToState = options => {
|
||||||
let cachedRedirect = get(routify.redirect)
|
let cachedRedirect = get(routify.redirect)
|
||||||
let cachedPage = get(routify.page)
|
let cachedPage = get(routify.page)
|
||||||
let previousParamsHash = null
|
let previousParamsHash = null
|
||||||
let debug = true
|
let debug = false
|
||||||
const log = (...params) => debug && console.log(...params)
|
const log = (...params) => debug && console.log(...params)
|
||||||
|
|
||||||
// Navigate to a certain URL
|
// Navigate to a certain URL
|
||||||
|
|
|
@ -17,10 +17,7 @@
|
||||||
routify,
|
routify,
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(stopSyncing)
|
||||||
console.log("============= stop syncing screen ID!")
|
|
||||||
stopSyncing()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="design">
|
<div class="design">
|
||||||
|
|
|
@ -15,10 +15,7 @@
|
||||||
routify,
|
routify,
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(stopSyncing)
|
||||||
console.log("============= stop syncing component ID!")
|
|
||||||
stopSyncing()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Drawer } from "@budibase/bbui"
|
import { Button, Drawer } from "@budibase/bbui"
|
||||||
import NavigationDrawer from "./NavigationDrawer.svelte"
|
import NavigationLinksDrawer from "./NavigationLinksDrawer.svelte"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
|
|
||||||
|
@ -30,5 +30,5 @@
|
||||||
Configure the links in your navigation bar.
|
Configure the links in your navigation bar.
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<Button cta slot="buttons" on:click={save}>Save</Button>
|
<Button cta slot="buttons" on:click={save}>Save</Button>
|
||||||
<NavigationDrawer slot="body" bind:links />
|
<NavigationLinksDrawer slot="body" bind:links />
|
||||||
</Drawer>
|
</Drawer>
|
|
@ -1,7 +1,51 @@
|
||||||
<script>
|
<script>
|
||||||
import NavigationPanel from "components/design/navigation/NavigationPanel.svelte"
|
import NavigationPanel from "components/design/navigation/NavigationPanel.svelte"
|
||||||
import { Body, Layout } from "@budibase/bbui"
|
import {
|
||||||
import NavigationEditor from "./_components/NavigationEditor.svelte"
|
Body,
|
||||||
|
Layout,
|
||||||
|
Label,
|
||||||
|
ActionGroup,
|
||||||
|
ActionButton,
|
||||||
|
Checkbox,
|
||||||
|
Select,
|
||||||
|
ColorPicker,
|
||||||
|
Input,
|
||||||
|
notifications,
|
||||||
|
} from "@budibase/bbui"
|
||||||
|
import NavigationLinksEditor from "./_components/NavigationLinksEditor.svelte"
|
||||||
|
import { store } from "builderStore"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { DefaultAppTheme } from "constants"
|
||||||
|
|
||||||
|
const updateNavigation = async (key, value) => {
|
||||||
|
try {
|
||||||
|
let navigation = $store.navigation
|
||||||
|
navigation[key] = value
|
||||||
|
await store.actions.navigation.save(navigation)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error updating navigation settings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
// Add navigation settings to old apps
|
||||||
|
let changed = false
|
||||||
|
if (!$store.navigation.navigation) {
|
||||||
|
$store.navigation.navigation = "Top"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (!$store.navigation.hideTitle && !$store.navigation.title) {
|
||||||
|
$store.navigation.title = $store.name
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (!$store.navigation.width) {
|
||||||
|
$store.navigation.width = "Large"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
store.actions.navigation.save($store.navigation)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<NavigationPanel title="Navigation">
|
<NavigationPanel title="Navigation">
|
||||||
|
@ -13,6 +57,83 @@
|
||||||
You can hide and show your navigation for each screen in the screen
|
You can hide and show your navigation for each screen in the screen
|
||||||
settings
|
settings
|
||||||
</Body>
|
</Body>
|
||||||
<NavigationEditor />
|
<NavigationLinksEditor />
|
||||||
|
<Layout noPadding gap="XS">
|
||||||
|
<Label>Position</Label>
|
||||||
|
<ActionGroup quiet>
|
||||||
|
<ActionButton
|
||||||
|
selected={$store.navigation.navigation === "Top"}
|
||||||
|
quiet={$store.navigation.navigation !== "Top"}
|
||||||
|
icon="PaddingTop"
|
||||||
|
on:click={() => updateNavigation("navigation", "Top")}
|
||||||
|
/>
|
||||||
|
<ActionButton
|
||||||
|
selected={$store.navigation.navigation === "Left"}
|
||||||
|
quiet={$store.navigation.navigation !== "Left"}
|
||||||
|
icon="PaddingLeft"
|
||||||
|
on:click={() => updateNavigation("navigation", "Left")}
|
||||||
|
/>
|
||||||
|
</ActionGroup>
|
||||||
|
</Layout>
|
||||||
|
{#if $store.navigation.navigation === "Top"}
|
||||||
|
<Checkbox
|
||||||
|
text="Sticky header"
|
||||||
|
value={$store.navigation.sticky}
|
||||||
|
on:change={e => updateNavigation("sticky", e.detail)}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<Layout noPadding gap="XS">
|
||||||
|
<Checkbox
|
||||||
|
text="Logo"
|
||||||
|
value={!$store.navigation.hideLogo}
|
||||||
|
on:change={e => updateNavigation("hideLogo", !e.detail)}
|
||||||
|
/>
|
||||||
|
{#if !$store.navigation.hideLogo}
|
||||||
|
<Input
|
||||||
|
value={$store.navigation.logoUrl}
|
||||||
|
on:change={e => updateNavigation("logoUrl", e.detail)}
|
||||||
|
placeholder="Add logo URL"
|
||||||
|
updateOnChange={false}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</Layout>
|
||||||
|
<Layout noPadding gap="XS">
|
||||||
|
<Checkbox
|
||||||
|
text="Title"
|
||||||
|
value={!$store.navigation.hideTitle}
|
||||||
|
on:change={e => updateNavigation("hideTitle", !e.detail)}
|
||||||
|
/>
|
||||||
|
{#if !$store.navigation.hideTitle}
|
||||||
|
<Input
|
||||||
|
value={$store.navigation.title}
|
||||||
|
on:change={e => updateNavigation("title", e.detail)}
|
||||||
|
placeholder="Add title"
|
||||||
|
updateOnChange={false}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</Layout>
|
||||||
|
<Select
|
||||||
|
label="Width"
|
||||||
|
options={["Max", "Large", "Medium", "Small"]}
|
||||||
|
plaveholder={null}
|
||||||
|
value={$store.navigation.navWidth}
|
||||||
|
on:change={e => updateNavigation("navWidth", e.detail)}
|
||||||
|
/>
|
||||||
|
<Layout noPadding gap="XS">
|
||||||
|
<Label>Background color</Label>
|
||||||
|
<ColorPicker
|
||||||
|
spectrumTheme={$store.theme}
|
||||||
|
value={$store.navigation.navBackground || DefaultAppTheme.navBackground}
|
||||||
|
on:change={e => updateNavigation("navBackground", e.detail)}
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
|
<Layout noPadding gap="XS">
|
||||||
|
<Label>Text color</Label>
|
||||||
|
<ColorPicker
|
||||||
|
spectrumTheme={$store.theme}
|
||||||
|
value={$store.navigation.navTextColor || DefaultAppTheme.navTextColor}
|
||||||
|
on:change={e => updateNavigation("navTextColor", e.detail)}
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
</NavigationPanel>
|
</NavigationPanel>
|
||||||
|
|
|
@ -13,17 +13,10 @@
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import AppThemeSelect from "./AppThemeSelect.svelte"
|
import AppThemeSelect from "./AppThemeSelect.svelte"
|
||||||
|
import { DefaultAppTheme } from "constants"
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
|
||||||
const defaultTheme = {
|
|
||||||
primaryColor: "var(--spectrum-global-color-blue-600)",
|
|
||||||
primaryColorHover: "var(--spectrum-global-color-blue-500)",
|
|
||||||
buttonBorderRadius: "16px",
|
|
||||||
navBackground: "var(--spectrum-global-color-gray-50)",
|
|
||||||
navTextColor: "var(--spectrum-global-color-gray-800)",
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonBorderRadiusOptions = [
|
const buttonBorderRadiusOptions = [
|
||||||
{
|
{
|
||||||
label: "None",
|
label: "None",
|
||||||
|
@ -93,7 +86,7 @@
|
||||||
<Select
|
<Select
|
||||||
placeholder={null}
|
placeholder={null}
|
||||||
value={$store.customTheme?.buttonBorderRadius ||
|
value={$store.customTheme?.buttonBorderRadius ||
|
||||||
defaultTheme.buttonBorderRadius}
|
DefaultAppTheme.buttonBorderRadius}
|
||||||
on:change={updateProperty("buttonBorderRadius")}
|
on:change={updateProperty("buttonBorderRadius")}
|
||||||
options={buttonBorderRadiusOptions}
|
options={buttonBorderRadiusOptions}
|
||||||
/>
|
/>
|
||||||
|
@ -103,7 +96,8 @@
|
||||||
<Label size="L">Accent color</Label>
|
<Label size="L">Accent color</Label>
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
spectrumTheme={$store.theme}
|
spectrumTheme={$store.theme}
|
||||||
value={$store.customTheme?.primaryColor || defaultTheme.primaryColor}
|
value={$store.customTheme?.primaryColor ||
|
||||||
|
DefaultAppTheme.primaryColor}
|
||||||
on:change={updateProperty("primaryColor")}
|
on:change={updateProperty("primaryColor")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -112,27 +106,10 @@
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
spectrumTheme={$store.theme}
|
spectrumTheme={$store.theme}
|
||||||
value={$store.customTheme?.primaryColorHover ||
|
value={$store.customTheme?.primaryColorHover ||
|
||||||
defaultTheme.primaryColorHover}
|
DefaultAppTheme.primaryColorHover}
|
||||||
on:change={updateProperty("primaryColorHover")}
|
on:change={updateProperty("primaryColorHover")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting">
|
|
||||||
<Label size="L">Navigation bar background color</Label>
|
|
||||||
<ColorPicker
|
|
||||||
spectrumTheme={$store.theme}
|
|
||||||
value={$store.customTheme?.navBackground ||
|
|
||||||
defaultTheme.navBackground}
|
|
||||||
on:change={updateProperty("navBackground")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="setting">
|
|
||||||
<Label size="L">Navigation bar text color</Label>
|
|
||||||
<ColorPicker
|
|
||||||
spectrumTheme={$store.theme}
|
|
||||||
value={$store.customTheme?.navTextColor || defaultTheme.navTextColor}
|
|
||||||
on:change={updateProperty("navTextColor")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<Button secondary quiet on:click={resetTheme}>Reset</Button>
|
<Button secondary quiet on:click={resetTheme}>Reset</Button>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
const context = getContext("context")
|
const context = getContext("context")
|
||||||
|
|
||||||
|
// Legacy props which must remain unchanged for backwards compatibility
|
||||||
export let title
|
export let title
|
||||||
export let hideTitle = false
|
export let hideTitle = false
|
||||||
export let logoUrl
|
export let logoUrl
|
||||||
|
@ -18,12 +19,18 @@
|
||||||
export let links
|
export let links
|
||||||
export let width = "Large"
|
export let width = "Large"
|
||||||
|
|
||||||
const navigationClasses = {
|
// New props from new design UI
|
||||||
|
export let navBackground
|
||||||
|
export let navTextColor
|
||||||
|
export let navWidth
|
||||||
|
export let pageWidth
|
||||||
|
|
||||||
|
const NavigationClasses = {
|
||||||
Top: "top",
|
Top: "top",
|
||||||
Left: "left",
|
Left: "left",
|
||||||
None: "none",
|
None: "none",
|
||||||
}
|
}
|
||||||
const widthClasses = {
|
const WidthClasses = {
|
||||||
Max: "max",
|
Max: "max",
|
||||||
Large: "l",
|
Large: "l",
|
||||||
Medium: "m",
|
Medium: "m",
|
||||||
|
@ -49,8 +56,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$: validLinks = links?.filter(link => link.text && link.url) || []
|
$: validLinks = links?.filter(link => link.text && link.url) || []
|
||||||
$: typeClass = navigationClasses[navigation] || "none"
|
$: typeClass = NavigationClasses[navigation] || NavigationClasses.None
|
||||||
$: widthClass = widthClasses[width] || "l"
|
$: navWidthClass = WidthClasses[navWidth || width] || WidthClasses.Large
|
||||||
|
$: pageWidthClass = WidthClasses[pageWidth || width] || WidthClasses.Large
|
||||||
|
$: navStyle = getNavStyle(
|
||||||
|
navBackground,
|
||||||
|
navTextColor,
|
||||||
|
$context.device.width,
|
||||||
|
$context.device.height
|
||||||
|
)
|
||||||
let mobileOpen = false
|
let mobileOpen = false
|
||||||
|
|
||||||
const isInternal = url => {
|
const isInternal = url => {
|
||||||
|
@ -83,6 +97,17 @@
|
||||||
return navigation === "Top" ? "137px" : "0px"
|
return navigation === "Top" ? "137px" : "0px"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getNavStyle = (backgroundColor, textColor, width, height) => {
|
||||||
|
let style = `--width:${width}px;--height:${height}px;`
|
||||||
|
if (backgroundColor) {
|
||||||
|
style += `--navBackground: ${backgroundColor};`
|
||||||
|
}
|
||||||
|
if (textColor) {
|
||||||
|
style += `--navTextColor: ${textColor};`
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -96,9 +121,9 @@
|
||||||
class="nav-wrapper"
|
class="nav-wrapper"
|
||||||
class:sticky
|
class:sticky
|
||||||
class:hidden={isPeeking}
|
class:hidden={isPeeking}
|
||||||
style={`--height:${$context.device.height}px; --width:${$context.device.width}px;`}
|
style={navStyle}
|
||||||
>
|
>
|
||||||
<div class="nav nav--{typeClass} size--{widthClass}">
|
<div class="nav nav--{typeClass} size--{navWidthClass}">
|
||||||
<div class="nav-header">
|
<div class="nav-header">
|
||||||
{#if validLinks?.length}
|
{#if validLinks?.length}
|
||||||
<div class="burger">
|
<div class="burger">
|
||||||
|
@ -165,7 +190,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="main-wrapper">
|
<div class="main-wrapper">
|
||||||
<div class="main size--{widthClass}">
|
<div class="main size--{pageWidthClass}">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,18 +47,17 @@ const createScreenStore = () => {
|
||||||
}
|
}
|
||||||
if (activeScreen?.showNavigation) {
|
if (activeScreen?.showNavigation) {
|
||||||
navigationSettings =
|
navigationSettings =
|
||||||
$builderStore.navigation || $appStore.application?.navigation
|
$builderStore.navigation || $appStore.application?.navigation || {}
|
||||||
|
|
||||||
// Legacy - if this is a legacy screen without any navigation
|
// Default navigation to top
|
||||||
// settings fall back to just showing the app title
|
|
||||||
if (!navigationSettings) {
|
|
||||||
navigationSettings = {
|
|
||||||
title: $appStore.application?.name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!navigationSettings.navigation) {
|
if (!navigationSettings.navigation) {
|
||||||
navigationSettings.navigation = "Top"
|
navigationSettings.navigation = "Top"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default title to app name
|
||||||
|
if (!navigationSettings.title && !navigationSettings.hideTitle) {
|
||||||
|
navigationSettings.title = $appStore.application?.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
activeLayout = {
|
activeLayout = {
|
||||||
_id: "layout",
|
_id: "layout",
|
||||||
|
|
Loading…
Reference in New Issue