Rewrite navigation settings panel
This commit is contained in:
parent
df52b6937a
commit
cdac78899a
|
@ -3,60 +3,59 @@
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import Panel from "components/design/Panel.svelte"
|
import Panel from "components/design/Panel.svelte"
|
||||||
import {
|
import {
|
||||||
Detail,
|
|
||||||
Toggle,
|
Toggle,
|
||||||
Body,
|
DetailSummary,
|
||||||
Icon,
|
|
||||||
ColorPicker,
|
|
||||||
Input,
|
|
||||||
Label,
|
|
||||||
ActionGroup,
|
|
||||||
ActionButton,
|
|
||||||
Checkbox,
|
Checkbox,
|
||||||
notifications,
|
notifications,
|
||||||
Select,
|
Select,
|
||||||
Combobox,
|
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import {
|
import {
|
||||||
themeStore,
|
themeStore,
|
||||||
selectedScreen,
|
selectedScreen,
|
||||||
screenStore,
|
screenStore,
|
||||||
navigationStore,
|
componentStore,
|
||||||
|
navigationStore as nav,
|
||||||
} from "stores/builder"
|
} from "stores/builder"
|
||||||
import { DefaultAppTheme } from "constants"
|
import { DefaultAppTheme } from "constants"
|
||||||
import BarButtonList from "/src/components/design/settings/controls/BarButtonList.svelte"
|
import PropertyControl from "components/design/settings/controls/PropertyControl.svelte"
|
||||||
|
import BarButtonList from "components/design/settings/controls/BarButtonList.svelte"
|
||||||
|
import ColorPicker from "components/design/settings/controls/ColorPicker.svelte"
|
||||||
|
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
|
||||||
|
import { getBindableProperties } from "dataBinding"
|
||||||
|
|
||||||
$: alignmentOptions = [
|
const positionOptions = [
|
||||||
|
{ value: "Top", barIcon: "PaddingTop" },
|
||||||
|
{ value: "Left", barIcon: "PaddingLeft" },
|
||||||
|
]
|
||||||
|
const alignmentOptions = [
|
||||||
{ value: "Left", barIcon: "TextAlignLeft" },
|
{ value: "Left", barIcon: "TextAlignLeft" },
|
||||||
{ value: "Center", barIcon: "TextAlignCenter" },
|
{ value: "Center", barIcon: "TextAlignCenter" },
|
||||||
{ value: "Right", barIcon: "TextAlignRight" },
|
{ value: "Right", barIcon: "TextAlignRight" },
|
||||||
]
|
]
|
||||||
|
const widthOptions = ["Max", "Large", "Medium", "Small"]
|
||||||
|
|
||||||
|
$: bindings = getBindableProperties(
|
||||||
|
$selectedScreen,
|
||||||
|
$componentStore.selectedComponentId
|
||||||
|
)
|
||||||
$: screenRouteOptions = $screenStore.screens
|
$: screenRouteOptions = $screenStore.screens
|
||||||
.map(screen => screen.routing?.route)
|
.map(screen => screen.routing?.route)
|
||||||
.filter(x => x != null)
|
.filter(x => x != null)
|
||||||
|
|
||||||
const updateShowNavigation = async e => {
|
const updateShowNavigation = async show => {
|
||||||
await screenStore.updateSetting(
|
await screenStore.updateSetting(get(selectedScreen), "showNavigation", show)
|
||||||
get(selectedScreen),
|
|
||||||
"showNavigation",
|
|
||||||
e.detail
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const update = async (key, value) => {
|
const update = async (key, value) => {
|
||||||
try {
|
try {
|
||||||
let navigation = $navigationStore
|
let navigation = $nav
|
||||||
navigation[key] = value
|
navigation[key] = value
|
||||||
await navigationStore.save(navigation)
|
await nav.save(navigation)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error updating navigation settings")
|
notifications.error("Error updating navigation settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateTextAlign = textAlignValue => {
|
|
||||||
navigationStore.syncAppNavigation({ textAlign: textAlignValue })
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Panel
|
<Panel
|
||||||
|
@ -65,215 +64,142 @@
|
||||||
borderLeft
|
borderLeft
|
||||||
wide
|
wide
|
||||||
>
|
>
|
||||||
<div class="generalSection">
|
<DetailSummary name="General" initiallyShow collapsible={false}>
|
||||||
<div class="subheading">
|
<PropertyControl
|
||||||
<Detail>General</Detail>
|
control={Toggle}
|
||||||
</div>
|
props={{ text: "Show nav on this screen" }}
|
||||||
<div class="toggle">
|
onChange={updateShowNavigation}
|
||||||
<Toggle
|
|
||||||
on:change={updateShowNavigation}
|
|
||||||
value={$selectedScreen?.showNavigation}
|
value={$selectedScreen?.showNavigation}
|
||||||
/>
|
/>
|
||||||
<Body size="S">Show nav on this screen</Body>
|
</DetailSummary>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if $selectedScreen?.showNavigation}
|
{#if $selectedScreen?.showNavigation}
|
||||||
<div class="divider" />
|
<DetailSummary name="Customize" initiallyShow collapsible={false}>
|
||||||
<div class="customizeSection">
|
|
||||||
<div class="subheading">
|
|
||||||
<Detail>Customize</Detail>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<Icon name="InfoOutline" size="S" />
|
|
||||||
<Body size="S">These settings apply to all screens</Body>
|
|
||||||
</div>
|
|
||||||
<div class="configureLinks">
|
|
||||||
<LinksEditor />
|
<LinksEditor />
|
||||||
</div>
|
<div class="settings">
|
||||||
<div class="controls">
|
<PropertyControl
|
||||||
<div class="label">
|
label="Position"
|
||||||
<Label size="M">Position</Label>
|
control={BarButtonList}
|
||||||
</div>
|
onChange={position => update("navigation", position)}
|
||||||
<ActionGroup quiet>
|
value={$nav.navigation}
|
||||||
<ActionButton
|
props={{
|
||||||
selected={$navigationStore.navigation === "Top"}
|
options: positionOptions,
|
||||||
quiet={$navigationStore.navigation !== "Top"}
|
}}
|
||||||
icon="PaddingTop"
|
|
||||||
on:click={() => update("navigation", "Top")}
|
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
{#if $nav.navigation === "Top"}
|
||||||
selected={$navigationStore.navigation === "Left"}
|
<PropertyControl
|
||||||
quiet={$navigationStore.navigation !== "Left"}
|
label="Sticky header"
|
||||||
icon="PaddingLeft"
|
control={Checkbox}
|
||||||
on:click={() => update("navigation", "Left")}
|
value={$nav.sticky}
|
||||||
|
onChange={width => update("navWidth", width)}
|
||||||
/>
|
/>
|
||||||
</ActionGroup>
|
<PropertyControl
|
||||||
|
label="Width"
|
||||||
{#if $navigationStore.navigation === "Top"}
|
control={Select}
|
||||||
<div class="label">
|
onChange={position => update("navigation", position)}
|
||||||
<Label size="M">Sticky header</Label>
|
value={$nav.navWidth}
|
||||||
</div>
|
props={{
|
||||||
<Checkbox
|
placeholder: null,
|
||||||
value={$navigationStore.sticky}
|
options: widthOptions,
|
||||||
on:change={e => update("sticky", e.detail)}
|
}}
|
||||||
/>
|
|
||||||
<div class="label">
|
|
||||||
<Label size="M">Width</Label>
|
|
||||||
</div>
|
|
||||||
<Select
|
|
||||||
options={["Max", "Large", "Medium", "Small"]}
|
|
||||||
plaveholder={null}
|
|
||||||
value={$navigationStore.navWidth}
|
|
||||||
on:change={e => update("navWidth", e.detail)}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label size="M">Show title</Label>
|
label="Show title"
|
||||||
</div>
|
control={Checkbox}
|
||||||
<Checkbox
|
value={!$nav.hideTitle}
|
||||||
value={!$navigationStore.hideTitle}
|
onChange={show => update("hideTitle", !show)}
|
||||||
on:change={e => update("hideTitle", !e.detail)}
|
|
||||||
/>
|
/>
|
||||||
{#if !$navigationStore.hideTitle}
|
{#if !$nav.hideTitle}
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label size="M">Title</Label>
|
label="Title"
|
||||||
</div>
|
control={DrawerBindableInput}
|
||||||
<Input
|
value={$nav.title}
|
||||||
value={$navigationStore.title}
|
onChange={title => update("title", title)}
|
||||||
on:change={e => update("title", e.detail)}
|
{bindings}
|
||||||
updateOnChange={false}
|
props={{
|
||||||
|
updateOnChange: false,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
<PropertyControl
|
||||||
<div class="label">
|
label="Text align"
|
||||||
<Label size="M">Text align</Label>
|
control={BarButtonList}
|
||||||
</div>
|
onChange={align => nav.syncAppNavigation({ textAlign: align })}
|
||||||
<BarButtonList
|
value={$nav.textAlign}
|
||||||
options={alignmentOptions}
|
props={{
|
||||||
value={$navigationStore.textAlign}
|
options: alignmentOptions,
|
||||||
onChange={updateTextAlign}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label>Background</Label>
|
label="Background"
|
||||||
</div>
|
control={ColorPicker}
|
||||||
<ColorPicker
|
onChange={color => update("navBackground", color)}
|
||||||
spectrumTheme={$themeStore.theme}
|
value={$nav.navBackground || DefaultAppTheme.navBackground}
|
||||||
value={$navigationStore.navBackground ||
|
props={{
|
||||||
DefaultAppTheme.navBackground}
|
spectrumTheme: $themeStore.theme,
|
||||||
on:change={e => update("navBackground", e.detail)}
|
}}
|
||||||
/>
|
/>
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label>Text</Label>
|
label="Text"
|
||||||
</div>
|
control={ColorPicker}
|
||||||
<ColorPicker
|
onChange={color => update("navTextColor", color)}
|
||||||
spectrumTheme={$themeStore.theme}
|
value={$nav.navTextColor || DefaultAppTheme.navTextColor}
|
||||||
value={$navigationStore.navTextColor || DefaultAppTheme.navTextColor}
|
props={{
|
||||||
on:change={e => update("navTextColor", e.detail)}
|
spectrumTheme: $themeStore.theme,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</DetailSummary>
|
||||||
|
|
||||||
<div class="divider" />
|
<DetailSummary name="Logo" initiallyShow collapsible={false}>
|
||||||
<div class="customizeSection">
|
<div class="settings">
|
||||||
<div class="subheading">
|
<PropertyControl
|
||||||
<Detail>Logo</Detail>
|
label="Show logo"
|
||||||
</div>
|
control={Checkbox}
|
||||||
<div class="controls">
|
value={!$nav.hideLogo}
|
||||||
<div class="label">
|
onChange={show => update("hideLogo", !show)}
|
||||||
<Label size="M">Show logo</Label>
|
|
||||||
</div>
|
|
||||||
<Checkbox
|
|
||||||
value={!$navigationStore.hideLogo}
|
|
||||||
on:change={e => update("hideLogo", !e.detail)}
|
|
||||||
/>
|
/>
|
||||||
{#if !$navigationStore.hideLogo}
|
{#if !$nav.hideLogo}
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label size="M">Logo image URL</Label>
|
label="Logo image URL"
|
||||||
</div>
|
control={DrawerBindableInput}
|
||||||
<Input
|
value={$nav.logoUrl}
|
||||||
value={$navigationStore.logoUrl}
|
onChange={url => update("logoUrl", url)}
|
||||||
on:change={e => update("logoUrl", e.detail)}
|
{bindings}
|
||||||
updateOnChange={false}
|
props={{
|
||||||
|
updateOnChange: false,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label size="M">Logo link URL</Label>
|
label="Logo link URL"
|
||||||
</div>
|
control={DrawerBindableCombobox}
|
||||||
<Combobox
|
value={$nav.logoLinkUrl}
|
||||||
value={$navigationStore.logoLinkUrl}
|
onChange={url => update("logoLinkUrl", url)}
|
||||||
on:change={e => update("logoLinkUrl", e.detail)}
|
{bindings}
|
||||||
options={screenRouteOptions}
|
props={{
|
||||||
|
appendBindingsAsOptions: false,
|
||||||
|
options: screenRouteOptions,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div class="label">
|
<PropertyControl
|
||||||
<Label size="M">New tab</Label>
|
label="New tab"
|
||||||
</div>
|
control={Checkbox}
|
||||||
<Checkbox
|
value={$nav.openLogoLinkInNewTab}
|
||||||
value={!!$navigationStore.openLogoLinkInNewTab}
|
onChange={show => update("openLogoLinkInNewTab", show)}
|
||||||
on:change={e => update("openLogoLinkInNewTab", !!e.detail)}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</DetailSummary>
|
||||||
{/if}
|
{/if}
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.generalSection {
|
.settings {
|
||||||
padding: 13px 13px 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.customizeSection {
|
|
||||||
padding: 13px 13px 25px;
|
|
||||||
}
|
|
||||||
.subheading {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subheading :global(p) {
|
|
||||||
color: var(--grey-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
}
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
.divider {
|
gap: 8px;
|
||||||
border-top: 1px solid var(--grey-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.controls {
|
|
||||||
position: relative;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 90px 1fr;
|
|
||||||
align-items: start;
|
|
||||||
transition: background 130ms ease-out, border-color 130ms ease-out;
|
|
||||||
border-left: 4px solid transparent;
|
|
||||||
margin: 0 calc(-1 * var(--spacing-xl));
|
|
||||||
padding: 0 var(--spacing-xl) 0 calc(var(--spacing-xl) - 4px);
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
margin-top: 16px;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
background-color: var(--background-alt);
|
|
||||||
padding: 12px;
|
|
||||||
display: flex;
|
|
||||||
border-radius: 4px;
|
|
||||||
gap: 4px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
.info :global(svg) {
|
|
||||||
margin-right: 5px;
|
|
||||||
color: var(--spectrum-global-color-gray-600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.configureLinks :global(button) {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue