Remove lightest and dark themes, use enums for themes, standardise naming
This commit is contained in:
parent
8466f8883c
commit
247d57887a
|
@ -141,13 +141,13 @@
|
||||||
icon: "ShareAndroid",
|
icon: "ShareAndroid",
|
||||||
action: () => $goto(`./automation/${automation._id}`),
|
action: () => $goto(`./automation/${automation._id}`),
|
||||||
})) ?? []),
|
})) ?? []),
|
||||||
...Constants.Themes.map(theme => ({
|
...Constants.ThemeOptions.map(theme => ({
|
||||||
type: "Change Builder Theme",
|
type: "Change Builder Theme",
|
||||||
name: theme.name,
|
name: theme.name,
|
||||||
icon: "ColorPalette",
|
icon: "ColorPalette",
|
||||||
action: () =>
|
action: () =>
|
||||||
themeStore.update(state => {
|
themeStore.update(state => {
|
||||||
state.theme = theme.class
|
state.theme = theme.id
|
||||||
return state
|
return state
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
<ModalContent title="Theme">
|
<ModalContent title="Theme">
|
||||||
<Select
|
<Select
|
||||||
options={Constants.Themes}
|
options={Constants.ThemeOptions}
|
||||||
bind:value={$themeStore.theme}
|
bind:value={$themeStore.theme}
|
||||||
placeholder={null}
|
placeholder={null}
|
||||||
getOptionLabel={x => x.name}
|
getOptionLabel={x => x.name}
|
||||||
getOptionValue={x => x.class}
|
getOptionValue={x => x.id}
|
||||||
/>
|
/>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
import { themeStore, appStore } from "stores/builder"
|
import { themeStore, appStore } from "stores/builder"
|
||||||
import { Constants } from "@budibase/frontend-core"
|
import { Constants, getThemeClassNames } from "@budibase/frontend-core"
|
||||||
|
|
||||||
const onChangeTheme = async theme => {
|
const onChangeTheme = async theme => {
|
||||||
try {
|
try {
|
||||||
await themeStore.save(`spectrum--${theme}`, $appStore.appId)
|
await themeStore.save(theme, $appStore.appId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error updating theme")
|
notifications.error("Error updating theme")
|
||||||
}
|
}
|
||||||
|
@ -15,16 +15,13 @@
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{#each Constants.Themes as theme}
|
{#each Constants.ThemeOptions as theme}
|
||||||
<div
|
<div
|
||||||
class="theme"
|
class="theme"
|
||||||
class:selected={`spectrum--${theme.class}` === $themeStore.theme}
|
class:selected={theme.id === $themeStore.theme}
|
||||||
on:click={() => onChangeTheme(theme.class)}
|
on:click={() => onChangeTheme(theme.id)}
|
||||||
>
|
>
|
||||||
<div
|
<div class="color {getThemeClassNames(theme.id)}" />
|
||||||
style="background: {theme.preview}"
|
|
||||||
class="color spectrum--{theme.class}"
|
|
||||||
/>
|
|
||||||
{theme.name}
|
{theme.name}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -21,7 +21,10 @@
|
||||||
import { sdk } from "@budibase/shared-core"
|
import { sdk } from "@budibase/shared-core"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import ErrorSVG from "./ErrorSVG.svelte"
|
import ErrorSVG from "./ErrorSVG.svelte"
|
||||||
import { getBaseTheme, ClientAppSkeleton } from "@budibase/frontend-core"
|
import {
|
||||||
|
ClientAppSkeleton,
|
||||||
|
getThemeClassNames,
|
||||||
|
} from "@budibase/frontend-core"
|
||||||
import { contextMenuStore } from "stores/builder"
|
import { contextMenuStore } from "stores/builder"
|
||||||
|
|
||||||
$: app = $enrichedApps.find(app => app.appId === $params.appId)
|
$: app = $enrichedApps.find(app => app.appId === $params.appId)
|
||||||
|
@ -163,9 +166,7 @@
|
||||||
class:hide={!loading || !app?.features?.skeletonLoader}
|
class:hide={!loading || !app?.features?.skeletonLoader}
|
||||||
class="loading"
|
class="loading"
|
||||||
>
|
>
|
||||||
<div
|
<div class="loadingThemeWrapper {getThemeClassNames(app.theme)}">
|
||||||
class={`loadingThemeWrapper ${getBaseTheme(app.theme)} ${app.theme}`}
|
|
||||||
>
|
|
||||||
<ClientAppSkeleton
|
<ClientAppSkeleton
|
||||||
noAnimation
|
noAnimation
|
||||||
hideDevTools={app?.status === "published"}
|
hideDevTools={app?.status === "published"}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { getBaseTheme } from "@budibase/frontend-core"
|
import { Constants, ensureValidTheme } from "@budibase/frontend-core"
|
||||||
|
|
||||||
|
const DefaultAppTheme = Constants.Themes.Light
|
||||||
const INITIAL_THEMES_STATE = {
|
const INITIAL_THEMES_STATE = {
|
||||||
theme: "",
|
theme: DefaultAppTheme,
|
||||||
customTheme: {},
|
customTheme: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const themes = () => {
|
export const createThemeStore = () => {
|
||||||
const store = writable({
|
const store = writable({
|
||||||
...INITIAL_THEMES_STATE,
|
...INITIAL_THEMES_STATE,
|
||||||
})
|
})
|
||||||
|
|
||||||
const syncAppTheme = app => {
|
const syncAppTheme = app => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const theme = app.theme || "spectrum--light"
|
const theme = ensureValidTheme(app.theme, DefaultAppTheme)
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
theme,
|
theme,
|
||||||
baseTheme: getBaseTheme(theme),
|
|
||||||
customTheme: app.customTheme,
|
customTheme: app.customTheme,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -51,7 +51,7 @@ export const themes = () => {
|
||||||
const { theme, customTheme } = metadata
|
const { theme, customTheme } = metadata
|
||||||
store.update(state => ({
|
store.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
theme,
|
theme: ensureValidTheme(theme, DefaultAppTheme),
|
||||||
customTheme,
|
customTheme,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -66,4 +66,4 @@ export const themes = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const themeStore = themes()
|
export const themeStore = createThemeStore()
|
||||||
|
|
|
@ -1,38 +1,36 @@
|
||||||
import { Constants, createLocalStorageStore } from "@budibase/frontend-core"
|
import {
|
||||||
|
Constants,
|
||||||
|
createLocalStorageStore,
|
||||||
|
ensureValidTheme,
|
||||||
|
getThemeClassNames,
|
||||||
|
} from "@budibase/frontend-core"
|
||||||
|
import { derived } from "svelte/store"
|
||||||
|
|
||||||
export const getThemeStore = () => {
|
export const getThemeStore = () => {
|
||||||
|
const defaultBuilderTheme = Constants.Themes.Darkest
|
||||||
const themeElement = document.documentElement
|
const themeElement = document.documentElement
|
||||||
|
|
||||||
const initialValue = {
|
const initialValue = {
|
||||||
theme: "darkest",
|
theme: defaultBuilderTheme,
|
||||||
}
|
}
|
||||||
const store = createLocalStorageStore("bb-theme", initialValue)
|
const store = createLocalStorageStore("bb-theme", initialValue)
|
||||||
|
const derivedStore = derived(store, $store => ({
|
||||||
|
...$store,
|
||||||
|
theme: ensureValidTheme($store.theme, defaultBuilderTheme),
|
||||||
|
}))
|
||||||
|
|
||||||
// Update theme class when store changes
|
// Update theme class when store changes
|
||||||
store.subscribe(state => {
|
derivedStore.subscribe(({ theme }) => {
|
||||||
// Handle any old local storage values - this can be removed after the update
|
const classNames = getThemeClassNames(theme).split(" ")
|
||||||
if (state.darkMode !== undefined) {
|
Constants.ThemeOptions.forEach(option => {
|
||||||
store.set(initialValue)
|
const className = `${Constants.ThemeClassPrefix}${option.id}`
|
||||||
return
|
themeElement.classList.toggle(className, classNames.includes(className))
|
||||||
}
|
|
||||||
|
|
||||||
// Update global class names to use the new theme and remove others
|
|
||||||
Constants.Themes.forEach(option => {
|
|
||||||
themeElement.classList.toggle(
|
|
||||||
`spectrum--${option.class}`,
|
|
||||||
option.class === state.theme
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add base theme if required
|
|
||||||
const selectedTheme = Constants.Themes.find(x => x.class === state.theme)
|
|
||||||
if (selectedTheme?.base) {
|
|
||||||
themeElement.classList.add(`spectrum--${selectedTheme.base}`)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return store
|
return {
|
||||||
|
...store,
|
||||||
|
subscribe: derivedStore.subscribe,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ?? confusion
|
|
||||||
export const themeStore = getThemeStore()
|
export const themeStore = getThemeStore()
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
import { setContext, onMount } from "svelte"
|
import { setContext, onMount } from "svelte"
|
||||||
import { Layout, Heading, Body } from "@budibase/bbui"
|
import { Layout, Heading, Body } from "@budibase/bbui"
|
||||||
import ErrorSVG from "@budibase/frontend-core/assets/error.svg"
|
import ErrorSVG from "@budibase/frontend-core/assets/error.svg"
|
||||||
import { Constants, CookieUtils } from "@budibase/frontend-core"
|
import {
|
||||||
|
Constants,
|
||||||
|
CookieUtils,
|
||||||
|
getThemeClassNames,
|
||||||
|
} from "@budibase/frontend-core"
|
||||||
import Component from "./Component.svelte"
|
import Component from "./Component.svelte"
|
||||||
import SDK from "sdk"
|
import SDK from "sdk"
|
||||||
import {
|
import {
|
||||||
|
@ -154,7 +158,7 @@
|
||||||
id="spectrum-root"
|
id="spectrum-root"
|
||||||
lang="en"
|
lang="en"
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
class="spectrum spectrum--medium {$themeStore.baseTheme} {$themeStore.theme}"
|
class="spectrum spectrum--medium {getThemeClassNames($themeStore.theme)}"
|
||||||
class:builder={$builderStore.inBuilder}
|
class:builder={$builderStore.inBuilder}
|
||||||
class:show={fontsLoaded && dataLoaded}
|
class:show={fontsLoaded && dataLoaded}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { derived } from "svelte/store"
|
import { derived } from "svelte/store"
|
||||||
import { appStore } from "./app"
|
import { appStore } from "./app"
|
||||||
import { builderStore } from "./builder"
|
import { builderStore } from "./builder"
|
||||||
import { getBaseTheme } from "@budibase/frontend-core"
|
import { Constants, ensureValidTheme } from "@budibase/frontend-core"
|
||||||
|
|
||||||
// This is the good old acorn bug where having the word "g l o b a l" makes it
|
// This is the good old acorn bug where having the word "g l o b a l" makes it
|
||||||
// think that this is not ES6 compatible and starts throwing errors when using
|
// think that this is not ES6 compatible and starts throwing errors when using
|
||||||
// optional chaining. Piss off acorn.
|
// optional chaining. Piss off acorn.
|
||||||
const defaultTheme = "spectrum--light"
|
const defaultTheme = Constants.Themes.Light
|
||||||
const defaultCustomTheme = {
|
const defaultCustomTheme = {
|
||||||
primaryColor: "var(--spectrum-glo" + "bal-color-blue-600)",
|
primaryColor: "var(--spectrum-glo" + "bal-color-blue-600)",
|
||||||
primaryColorHover: "var(--spectrum-glo" + "bal-color-blue-500)",
|
primaryColorHover: "var(--spectrum-glo" + "bal-color-blue-500)",
|
||||||
|
@ -27,7 +27,7 @@ const createThemeStore = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure theme is set
|
// Ensure theme is set
|
||||||
theme = theme || defaultTheme
|
theme = ensureValidTheme(theme, defaultTheme)
|
||||||
|
|
||||||
// Delete and nullish keys from the custom theme
|
// Delete and nullish keys from the custom theme
|
||||||
if (customTheme) {
|
if (customTheme) {
|
||||||
|
@ -52,7 +52,6 @@ const createThemeStore = () => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme,
|
theme,
|
||||||
baseTheme: getBaseTheme(theme),
|
|
||||||
customTheme,
|
customTheme,
|
||||||
customThemeCss,
|
customThemeCss,
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,32 +108,34 @@ export const Roles = {
|
||||||
CREATOR: "CREATOR",
|
CREATOR: "CREATOR",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Themes = [
|
// Theming
|
||||||
|
export const ThemeClassPrefix = "spectrum--"
|
||||||
|
export const Themes = {
|
||||||
|
Lightest: "lightest",
|
||||||
|
Light: "light",
|
||||||
|
Dark: "dark",
|
||||||
|
Darkest: "darkest",
|
||||||
|
Nord: "nord",
|
||||||
|
Midnight: "midnight",
|
||||||
|
}
|
||||||
|
export const ThemeOptions = [
|
||||||
{
|
{
|
||||||
class: "lightest",
|
id: Themes.Light,
|
||||||
name: "Lightest",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
class: "light",
|
|
||||||
name: "Light",
|
name: "Light",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
class: "dark",
|
id: Themes.Darkest,
|
||||||
name: "Dark",
|
name: "Dark",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
class: "darkest",
|
id: Themes.Nord,
|
||||||
name: "Darkest",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
class: "nord",
|
|
||||||
name: "Nord",
|
name: "Nord",
|
||||||
base: "darkest",
|
base: Themes.Darkest,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
class: "midnight",
|
id: Themes.Midnight,
|
||||||
name: "Midnight",
|
name: "Midnight",
|
||||||
base: "darkest",
|
base: Themes.Darkest,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,41 @@
|
||||||
import { Themes } from "../constants.js"
|
import { Themes, ThemeOptions, ThemeClassPrefix } from "../constants.js"
|
||||||
|
|
||||||
export const getBaseTheme = theme => {
|
// Gets the CSS class names for the specified theme
|
||||||
if (!theme) {
|
export const getThemeClassNames = theme => {
|
||||||
return ""
|
theme = ensureValidTheme(theme)
|
||||||
}
|
let classNames = `${ThemeClassPrefix}${theme}`
|
||||||
let base = Themes.find(x => `spectrum--${x.class}` === theme)?.base || ""
|
|
||||||
|
// Prefix with base class if required
|
||||||
|
const base = ThemeOptions.find(x => x.id === theme)?.base
|
||||||
if (base) {
|
if (base) {
|
||||||
base = `spectrum--${base}`
|
classNames = `${ThemeClassPrefix}${base} ${classNames}`
|
||||||
}
|
}
|
||||||
return base
|
|
||||||
|
return classNames
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures a theme value is a valid option
|
||||||
|
export const ensureValidTheme = (theme, fallback = Themes.Darkest) => {
|
||||||
|
// Default to darkest
|
||||||
|
if (!theme) {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we aren't using the spectrum prefix
|
||||||
|
if (theme.startsWith(ThemeClassPrefix)) {
|
||||||
|
theme = theme.split(ThemeClassPrefix)[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we aren't using a deprecated theme, and migrate
|
||||||
|
// to the nearest valid theme if we are
|
||||||
|
if (!ThemeOptions.some(x => x.id === theme)) {
|
||||||
|
if (theme === Themes.Lightest) {
|
||||||
|
return Themes.Light
|
||||||
|
} else if (theme === Themes.Dark) {
|
||||||
|
return Themes.Darkest
|
||||||
|
} else {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theme
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue