Merge pull request #11296 from Budibase/screen-theme-rightpanel

Screen Settings/Theme UI updated and moved
This commit is contained in:
Andrew Kingston 2023-08-23 17:36:36 +01:00 committed by GitHub
commit d0854c2fec
12 changed files with 300 additions and 103 deletions

View File

@ -32,11 +32,10 @@ export default function positionDropdown(element, opts) {
left: null, left: null,
top: null, top: null,
} }
// Determine vertical styles // Determine vertical styles
if (align === "right-outside") { if (align === "right-outside") {
styles.top = anchorBounds.top styles.top = anchorBounds.top
} else if (window.innerHeight - anchorBounds.bottom < 100) { } else if (window.innerHeight - anchorBounds.bottom < (maxHeight || 100)) {
styles.top = anchorBounds.top - elementBounds.height - offset styles.top = anchorBounds.top - elementBounds.height - offset
styles.maxHeight = maxHeight || 240 styles.maxHeight = maxHeight || 240
} else { } else {

View File

@ -1,8 +1,8 @@
<script> <script>
import Popover from "../Popover/Popover.svelte"
import Layout from "../Layout/Layout.svelte"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import "@spectrum-css/popover/dist/index-vars.css" import "@spectrum-css/popover/dist/index-vars.css"
import clickOutside from "../Actions/click_outside"
import { fly } from "svelte/transition"
import Icon from "../Icon/Icon.svelte" import Icon from "../Icon/Icon.svelte"
import Input from "../Form/Input.svelte" import Input from "../Form/Input.svelte"
import { capitalise } from "../helpers" import { capitalise } from "../helpers"
@ -10,9 +10,11 @@
export let value export let value
export let size = "M" export let size = "M"
export let spectrumTheme export let spectrumTheme
export let alignRight = false export let offset
export let align
let open = false let dropdown
let preview
$: customValue = getCustomValue(value) $: customValue = getCustomValue(value)
$: checkColor = getCheckColor(value) $: checkColor = getCheckColor(value)
@ -82,7 +84,7 @@
const onChange = value => { const onChange = value => {
dispatch("change", value) dispatch("change", value)
open = false dropdown.hide()
} }
const getCustomValue = value => { const getCustomValue = value => {
@ -119,30 +121,25 @@
return "var(--spectrum-global-color-static-gray-900)" return "var(--spectrum-global-color-static-gray-900)"
} }
const handleOutsideClick = event => {
if (open) {
event.stopPropagation()
open = false
}
}
</script> </script>
<div class="container"> <div
<div class="preview size--{size || 'M'}" on:click={() => (open = true)}> bind:this={preview}
<div class="preview size--{size || 'M'}"
class="fill {spectrumTheme || ''}" on:click={() => {
style={value ? `background: ${value};` : ""} dropdown.toggle()
class:placeholder={!value} }}
/> >
</div> <div
{#if open} class="fill {spectrumTheme || ''}"
<div style={value ? `background: ${value};` : ""}
use:clickOutside={handleOutsideClick} class:placeholder={!value}
transition:fly|local={{ y: -20, duration: 200 }} />
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" </div>
class:spectrum-Popover--align-right={alignRight}
> <Popover bind:this={dropdown} anchor={preview} maxHeight={320} {offset} {align}>
<Layout paddingX="XL" paddingY="L">
<div class="container">
{#each categories as category} {#each categories as category}
<div class="category"> <div class="category">
<div class="heading">{category.label}</div> <div class="heading">{category.label}</div>
@ -187,8 +184,8 @@
</div> </div>
</div> </div>
</div> </div>
{/if} </Layout>
</div> </Popover>
<style> <style>
.container { .container {
@ -248,20 +245,6 @@
width: 48px; width: 48px;
height: 48px; height: 48px;
} }
.spectrum-Popover {
width: 210px;
z-index: 999;
top: 100%;
padding: var(--spacing-l) var(--spacing-xl);
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: var(--spacing-xl);
}
.spectrum-Popover--align-right {
right: 0;
}
.colors { .colors {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
@ -297,7 +280,11 @@
.category--custom .heading { .category--custom .heading {
margin-bottom: var(--spacing-xs); margin-bottom: var(--spacing-xs);
} }
.container {
display: flex;
flex-direction: column;
gap: var(--spacing-xl);
}
.spectrum-wrapper { .spectrum-wrapper {
background-color: transparent; background-color: transparent;
} }

View File

@ -35,6 +35,14 @@
open = false open = false
} }
export const toggle = () => {
if (!open) {
show()
} else {
hide()
}
}
const handleOutsideClick = e => { const handleOutsideClick = e => {
if (open) { if (open) {
// Stop propagation if the source is the anchor // Stop propagation if the source is the anchor

View File

@ -42,7 +42,6 @@
<ColorPicker <ColorPicker
value={column.background} value={column.background}
on:change={e => (column.background = e.detail)} on:change={e => (column.background = e.detail)}
alignRight
spectrumTheme={$store.theme} spectrumTheme={$store.theme}
/> />
</Layout> </Layout>
@ -51,7 +50,6 @@
<ColorPicker <ColorPicker
value={column.color} value={column.color}
on:change={e => (column.color = e.detail)} on:change={e => (column.color = e.detail)}
alignRight
spectrumTheme={$store.theme} spectrumTheme={$store.theme}
/> />
</Layout> </Layout>

View File

@ -64,10 +64,8 @@
<Detail>Customize</Detail> <Detail>Customize</Detail>
</div> </div>
<div class="info"> <div class="info">
<div class="infoHeader"> <Icon name="InfoOutline" size="S" />
<Icon name="InfoOutline" /> <Body size="S">These settings apply to all screens</Body>
<Body size="S">These settings apply to all screens</Body>
</div>
</div> </div>
<div class="configureLinks"> <div class="configureLinks">
<LinksEditor /> <LinksEditor />
@ -210,22 +208,14 @@
.info { .info {
background-color: var(--background-alt); background-color: var(--background-alt);
padding: 12px; padding: 12px;
margin-bottom: 12px;
}
.infoHeader {
display: flex; display: flex;
margin-bottom: 5px;
border-radius: 4px; border-radius: 4px;
gap: 4px;
margin-bottom: 16px;
} }
.info :global(svg) {
.infoHeader :global(svg) {
margin-right: 5px; margin-right: 5px;
color: var(--grey-6); color: var(--spectrum-global-color-gray-600);
}
.infoHeader :global(p) {
color: var(--grey-7);
} }
.configureLinks :global(button) { .configureLinks :global(button) {

View File

@ -0,0 +1,64 @@
<script>
import { notifications } from "@budibase/bbui"
import { store } from "builderStore"
import { Constants } from "@budibase/frontend-core"
const onChangeTheme = async theme => {
try {
await store.actions.theme.save(`spectrum--${theme}`)
} catch (error) {
notifications.error("Error updating theme")
}
}
</script>
<div class="container">
{#each Constants.Themes as theme}
<div
class="theme"
class:selected={`spectrum--${theme.class}` === $store.theme}
on:click={() => onChangeTheme(theme.class)}
>
<div
style="background: {theme.preview}"
class="color spectrum--{theme.class}"
/>
{theme.name}
</div>
{/each}
</div>
<style>
.container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: var(--spacing-xs);
}
.color {
width: 20px;
height: 20px;
border-radius: 50px;
background: var(--spectrum-global-color-gray-200);
border: 1px solid rgba(0, 0, 0, 0.1);
}
.theme {
border-radius: 4px;
padding: var(--spacing-s) var(--spacing-m);
display: flex;
flex-direction: row;
align-items: center;
gap: var(--spacing-xl);
transition: background 130ms ease-out;
font-weight: 600;
color: var(--spectrum-global-color-gray-900);
}
.theme:hover {
cursor: pointer;
}
.theme.selected,
.theme:hover {
background: var(--spectrum-global-color-gray-50);
}
</style>

View File

@ -0,0 +1,38 @@
<script>
import { createEventDispatcher } from "svelte"
import { Slider, Button } from "@budibase/bbui"
export let customTheme
const dispatch = createEventDispatcher()
const options = ["0", "4px", "8px", "16px"]
$: index = options.indexOf(customTheme.buttonBorderRadius) ?? 2
const onChange = async e => {
dispatch("change", options[e.detail])
}
</script>
<div class="container">
<Slider min={0} max={3} step={1} value={index} on:change={onChange} />
<div class="button" style="--radius: {customTheme.buttonBorderRadius};">
<Button primary>Button</Button>
</div>
</div>
<style>
.container {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-xl);
}
.container :global(.spectrum-Form-item) {
flex: 1 1 auto;
}
.button :global(.spectrum-Button) {
border-radius: var(--radius) !important;
}
</style>

View File

@ -1,10 +1,8 @@
<script> <script>
import Panel from "components/design/Panel.svelte"
import { get } from "svelte/store" import { get } from "svelte/store"
import { Helpers } from "@budibase/bbui" import { Helpers } from "@budibase/bbui"
import { import {
Input, Input,
Layout,
Checkbox, Checkbox,
Banner, Banner,
Select, Select,
@ -133,33 +131,24 @@
} }
</script> </script>
<Panel {#if $selectedScreen.layoutId}
title={$selectedScreen.routing.route} <Banner
icon={$selectedScreen.routing.route === "/" ? "Home" : "WebPage"} type="warning"
borderLeft extraButtonText="Detach custom layout"
wide extraButtonAction={removeCustomLayout}
> showCloseButton={false}
<Layout gap="S" paddingX="L" paddingY="XL"> >
{#if $selectedScreen.layoutId} This screen uses a custom layout, which is deprecated
<Banner </Banner>
type="warning" {/if}
extraButtonText="Detach custom layout" {#each screenSettings as setting (setting.key)}
extraButtonAction={removeCustomLayout} <PropertyControl
showCloseButton={false} control={setting.control}
> label={setting.label}
This screen uses a custom layout, which is deprecated key={setting.key}
</Banner> value={Helpers.deepGet($selectedScreen, setting.key)}
{/if} onChange={val => setScreenSetting(setting, val)}
{#each screenSettings as setting (setting.key)} props={{ ...setting.props, error: errors[setting.key] }}
<PropertyControl {bindings}
control={setting.control} />
label={setting.label} {/each}
key={setting.key}
value={Helpers.deepGet($selectedScreen, setting.key)}
onChange={val => setScreenSetting(setting, val)}
props={{ ...setting.props, error: errors[setting.key] }}
{bindings}
/>
{/each}
</Layout>
</Panel>

View File

@ -0,0 +1,78 @@
<script>
import {
Layout,
Label,
ColorPicker,
notifications,
Icon,
Body,
} from "@budibase/bbui"
import { store } from "builderStore"
import { get } from "svelte/store"
import { DefaultAppTheme } from "constants"
import AppThemeSelect from "./AppThemeSelect.svelte"
import ButtonRoundnessSelect from "./ButtonRoundnessSelect.svelte"
import PropertyControl from "components/design/settings/controls/PropertyControl.svelte"
$: customTheme = $store.customTheme || {}
const update = async (property, value) => {
try {
store.actions.customTheme.save({
...get(store).customTheme,
[property]: value,
})
} catch (error) {
notifications.error("Error updating custom theme")
}
}
</script>
<div class="info">
<Icon name="InfoOutline" size="S" />
<Body size="S">These settings apply to all screens</Body>
</div>
<Layout noPadding gap="S">
<Layout noPadding gap="XS">
<AppThemeSelect />
</Layout>
<Layout noPadding gap="XS">
<Label>Button roundness</Label>
<ButtonRoundnessSelect
{customTheme}
on:change={e => update("buttonBorderRadius", e.detail)}
/>
</Layout>
<PropertyControl
label="Accent color"
control={ColorPicker}
value={customTheme.primaryColor || DefaultAppTheme.primaryColor}
onChange={val => update("primaryColor", val)}
props={{
spectrumTheme: $store.theme,
}}
/>
<PropertyControl
label="Hover"
control={ColorPicker}
value={customTheme.primaryColorHover || DefaultAppTheme.primaryColorHover}
onChange={val => update("primaryColorHover", val)}
props={{
spectrumTheme: $store.theme,
}}
/>
</Layout>
<style>
.info {
background-color: var(--background-alt);
padding: 12px;
display: flex;
border-radius: 4px;
gap: 4px;
}
.info :global(svg) {
margin-right: 5px;
color: var(--spectrum-global-color-gray-600);
}
</style>

View File

@ -0,0 +1,51 @@
<script>
import GeneralPanel from "./GeneralPanel.svelte"
import ThemePanel from "./ThemePanel.svelte"
import { selectedScreen } from "builderStore"
import Panel from "components/design/Panel.svelte"
import { capitalise } from "helpers"
import { ActionButton, Layout } from "@budibase/bbui"
let activeTab = "general"
const tabs = ["general", "theme"]
</script>
<Panel
title={$selectedScreen.routing.route}
icon={$selectedScreen.routing.route === "/" ? "Home" : "WebPage"}
borderLeft
wide
>
<div slot="panel-header-content">
<div class="settings-tabs">
{#each tabs as tab}
<ActionButton
size="M"
quiet
selected={activeTab === tab}
on:click={() => {
activeTab = tab
}}
>
{capitalise(tab)}
</ActionButton>
{/each}
</div>
</div>
<Layout gap="S" paddingX="L" paddingY="XL">
{#if activeTab === "theme"}
<ThemePanel />
{:else}
<GeneralPanel />
{/if}
</Layout>
</Panel>
<style>
.settings-tabs {
display: flex;
gap: var(--spacing-s);
padding: 0 var(--spacing-l);
padding-bottom: var(--spacing-l);
}
</style>

View File

@ -6,7 +6,7 @@
import { findComponent } from "builderStore/componentUtils" import { findComponent } from "builderStore/componentUtils"
import ComponentSettingsPanel from "./_components/Component/ComponentSettingsPanel.svelte" import ComponentSettingsPanel from "./_components/Component/ComponentSettingsPanel.svelte"
import NavigationPanel from "./_components/Navigation/index.svelte" import NavigationPanel from "./_components/Navigation/index.svelte"
import ScreenSettingsPanel from "./_components/Screen/SettingsPanel.svelte" import ScreenSettingsPanel from "./_components/Screen/index.svelte"
$: componentId = $store.selectedComponentId $: componentId = $store.selectedComponentId
$: store.actions.websocket.selectResource(componentId) $: store.actions.websocket.selectResource(componentId)

View File

@ -281,12 +281,7 @@ async function performAppCreate(ctx: UserCtx) {
title: name, title: name,
navWidth: "Large", navWidth: "Large",
navBackground: "var(--spectrum-global-color-gray-100)", navBackground: "var(--spectrum-global-color-gray-100)",
links: [ links: [],
{
url: "/home",
text: "Home",
},
],
}, },
theme: "spectrum--light", theme: "spectrum--light",
customTheme: { customTheme: {