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