Rewrite navigation settings panel

This commit is contained in:
Andrew Kingston 2024-03-26 16:05:01 +00:00
parent df52b6937a
commit cdac78899a
1 changed files with 136 additions and 210 deletions

View File

@ -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 value={$selectedScreen?.showNavigation}
on:change={updateShowNavigation} />
value={$selectedScreen?.showNavigation} </DetailSummary>
/>
<Body size="S">Show nav on this screen</Body>
</div>
</div>
{#if $selectedScreen?.showNavigation} {#if $selectedScreen?.showNavigation}
<div class="divider" /> <DetailSummary name="Customize" initiallyShow collapsible={false}>
<div class="customizeSection"> <LinksEditor />
<div class="subheading"> <div class="settings">
<Detail>Customize</Detail> <PropertyControl
</div> label="Position"
<div class="info"> control={BarButtonList}
<Icon name="InfoOutline" size="S" /> onChange={position => update("navigation", position)}
<Body size="S">These settings apply to all screens</Body> value={$nav.navigation}
</div> props={{
<div class="configureLinks"> options: positionOptions,
<LinksEditor /> }}
</div> />
<div class="controls"> {#if $nav.navigation === "Top"}
<div class="label"> <PropertyControl
<Label size="M">Position</Label> label="Sticky header"
</div> control={Checkbox}
<ActionGroup quiet> value={$nav.sticky}
<ActionButton onChange={width => update("navWidth", width)}
selected={$navigationStore.navigation === "Top"}
quiet={$navigationStore.navigation !== "Top"}
icon="PaddingTop"
on:click={() => update("navigation", "Top")}
/> />
<ActionButton <PropertyControl
selected={$navigationStore.navigation === "Left"} label="Width"
quiet={$navigationStore.navigation !== "Left"} control={Select}
icon="PaddingLeft" onChange={position => update("navigation", position)}
on:click={() => update("navigation", "Left")} value={$nav.navWidth}
/> props={{
</ActionGroup> placeholder: null,
options: widthOptions,
{#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)}
/> />
{/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>