From 1f5b1cfd10748a273c1152049b3c643cf7a0fa6f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 30 Oct 2020 13:23:49 +0000 Subject: [PATCH] Save theme settings to local storage and improve slider styles --- packages/builder/src/builderStore/index.js | 2 + .../src/builderStore/store/localStorage.js | 43 ++++++++++ .../builder/src/builderStore/store/theme.js | 38 ++++++++ .../components/settings/ThemeEditor.svelte | 86 +++++++++++++------ 4 files changed, 143 insertions(+), 26 deletions(-) create mode 100644 packages/builder/src/builderStore/store/localStorage.js create mode 100644 packages/builder/src/builderStore/store/theme.js diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 101f875e96..6317640955 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -1,11 +1,13 @@ import { getStore } from "./store" import { getBackendUiStore } from "./store/backend" import { getAutomationStore } from "./store/automation/" +import { getThemeStore } from "./store/theme" import analytics from "analytics" export const store = getStore() export const backendUiStore = getBackendUiStore() export const automationStore = getAutomationStore() +export const themeStore = getThemeStore() export const initialise = async () => { try { diff --git a/packages/builder/src/builderStore/store/localStorage.js b/packages/builder/src/builderStore/store/localStorage.js new file mode 100644 index 0000000000..aaf10460b6 --- /dev/null +++ b/packages/builder/src/builderStore/store/localStorage.js @@ -0,0 +1,43 @@ +import { get, writable } from "svelte/store" + +export const localStorageStore = (localStorageKey, initialValue) => { + const store = writable(initialValue, () => { + // Hydrate from local storage when we get a new subscriber + hydrate() + + // Listen for local storage changes and keep store in sync + const storageListener = ({ key }) => key === localStorageKey && hydrate() + window.addEventListener("storage", storageListener) + return () => window.removeEventListener("storage", storageListener) + }) + + // New store setter which updates the store and localstorage + const set = value => { + store.set(value) + localStorage.setItem(localStorageKey, JSON.stringify(value)) + } + + // New store updater which updates the store and localstorage + const update = updaterFn => set(updaterFn(get(store))) + + // Hydrates the store from localstorage + const hydrate = () => { + const localValue = localStorage.getItem(localStorageKey) + if (localValue == null) { + set(initialValue) + } else { + try { + store.set(JSON.parse(localValue)) + } catch { + set(initialValue) + } + } + } + + // Patch the default svelte store functions with our overrides + return { + ...store, + set, + update, + } +} diff --git a/packages/builder/src/builderStore/store/theme.js b/packages/builder/src/builderStore/store/theme.js new file mode 100644 index 0000000000..df94a4c3d5 --- /dev/null +++ b/packages/builder/src/builderStore/store/theme.js @@ -0,0 +1,38 @@ +import { localStorageStore } from "./localStorage" + +export const getThemeStore = () => { + const themeElement = document.documentElement + const initialValue = { + darkMode: false, + hue: 208, + saturation: 9, + lightness: 16, + } + + const store = localStorageStore("bb-theme", initialValue) + + // Sets a CSS variable on the root document element + function setCSSVariable(prop, value) { + themeElement.style.setProperty(prop, value) + } + + // Resets the custom theme to the default dark theme. + // The reset option is only available when dark theme is on, which is why it + // sets dark mode to true here + store.reset = () => { + store.set({ + ...initialValue, + darkMode: true, + }) + } + + // Update theme when store changes + store.subscribe(theme => { + themeElement.classList[theme.darkMode ? "add" : "remove"]("dark") + setCSSVariable("--theme-hue", Math.round(theme.hue)) + setCSSVariable("--theme-saturation", `${Math.round(theme.saturation)}%`) + setCSSVariable("--theme-brightness", `${Math.round(theme.lightness)}%`) + }) + + return store +} diff --git a/packages/builder/src/components/settings/ThemeEditor.svelte b/packages/builder/src/components/settings/ThemeEditor.svelte index 8355325e70..1c840d27f6 100644 --- a/packages/builder/src/components/settings/ThemeEditor.svelte +++ b/packages/builder/src/components/settings/ThemeEditor.svelte @@ -1,28 +1,10 @@
@@ -33,28 +15,36 @@
- +
- {#if dark && !showAdvanced} + {#if $themeStore.darkMode && !showAdvanced}
{/if} - {#if dark && showAdvanced} + {#if $themeStore.darkMode && showAdvanced}
- +
- +
- +
- +
{/if}
@@ -104,4 +94,48 @@ .button { align-self: flex-start; } + + input[type="range"] { + width: 100%; + margin: 0; + background-color: transparent; + -webkit-appearance: none; + } + input[type="range"]:focus { + outline: none; + } + input[type="range"]::-webkit-slider-runnable-track { + background: var(--grey-4); + border-radius: 9px; + width: 100%; + height: 18px; + cursor: pointer; + padding: 0 2px; + } + input[type="range"]::-webkit-slider-thumb { + width: 14px; + height: 14px; + background: white; + border-radius: 100%; + cursor: pointer; + -webkit-appearance: none; + border: none; + margin-top: 2px; + } + input[type="range"]::-moz-range-track { + background: var(--grey-4); + border-radius: 9px; + width: 100%; + height: 18px; + cursor: pointer; + padding: 0 2px; + } + input[type="range"]::-moz-range-thumb { + width: 14px; + height: 14px; + background: white; + border-radius: 100%; + cursor: pointer; + border: none; + }