diff --git a/docs/docs/documentation/getting-started/installation/backend-config.md b/docs/docs/documentation/getting-started/installation/backend-config.md index db52ee719..8998e5daf 100644 --- a/docs/docs/documentation/getting-started/installation/backend-config.md +++ b/docs/docs/documentation/getting-started/installation/backend-config.md @@ -75,3 +75,24 @@ Changing the webworker settings may cause unforeseen memory leak issues with Mea | LDAP_ID_ATTRIBUTE | uid | The LDAP attribute that maps to the user's id | | LDAP_NAME_ATTRIBUTE | name | The LDAP attribute that maps to the user's name | | LDAP_MAIL_ATTRIBUTE | mail | The LDAP attribute that maps to the user's email | + +### Themeing + +Setting the following environmental variables will change the theme of the frontend. Note that the themes are the same for all users. This is a break-change when migration from v0.x.x -> 1.x.x. + +| Variables | Default | Description | +| --------------------- | :-----: | --------------------------- | +| THEME_LIGHT_PRIMARY | #E58325 | Light Theme Config Variable | +| THEME_LIGHT_ACCENT | #007A99 | Light Theme Config Variable | +| THEME_LIGHT_SECONDARY | #973542 | Light Theme Config Variable | +| THEME_LIGHT_SUCCESS | #43A047 | Light Theme Config Variable | +| THEME_LIGHT_INFO | #1976D2 | Light Theme Config Variable | +| THEME_LIGHT_WARNING | #FF6D00 | Light Theme Config Variable | +| THEME_LIGHT_ERROR | #EF5350 | Light Theme Config Variable | +| THEME_DARK_PRIMARY | #E58325 | Dark Theme Config Variable | +| THEME_DARK_ACCENT | #007A99 | Dark Theme Config Variable | +| THEME_DARK_SECONDARY | #973542 | Dark Theme Config Variable | +| THEME_DARK_SUCCESS | #43A047 | Dark Theme Config Variable | +| THEME_DARK_INFO | #1976D2 | Dark Theme Config Variable | +| THEME_DARK_WARNING | #FF6D00 | Dark Theme Config Variable | +| THEME_DARK_ERROR | #EF5350 | Dark Theme Config Variable | diff --git a/frontend/plugins/theme.ts b/frontend/plugins/theme.ts index 577d266f7..6dd32fa1c 100644 --- a/frontend/plugins/theme.ts +++ b/frontend/plugins/theme.ts @@ -1,7 +1,60 @@ -import { Plugin } from "@nuxt/types" +import { Plugin } from "@nuxt/types"; -const themePlugin: Plugin = ({ $vuetify, $config }) => { - $vuetify.theme.themes = $config.themes as typeof $vuetify.theme.themes +export interface ThemeConfig { + lightPrimary: string; + lightAccent: string; + lightSecondary: string; + lightSuccess: string; + lightInfo: string; + lightWarning: string; + lightError: string; + darkPrimary: string; + darkAccent: string; + darkSecondary: string; + darkSuccess: string; + darkInfo: string; + darkWarning: string; + darkError: string; +} + +let __cachedTheme: ThemeConfig | undefined; + +async function fetchTheme(): Promise { + const route = "/api/app/about/theme"; + + try { + const response = await fetch(route); + const data = await response.json(); + return data as ThemeConfig; + } catch (error) { + return undefined; + } +} + +const themePlugin: Plugin = async ({ $vuetify, $config }) => { + let theme = __cachedTheme; + if (!theme) { + theme = await fetchTheme(); + __cachedTheme = theme; + } + + if (theme) { + $vuetify.theme.themes.light.primary = theme.lightPrimary; + $vuetify.theme.themes.light.accent = theme.lightAccent; + $vuetify.theme.themes.light.secondary = theme.lightSecondary; + $vuetify.theme.themes.light.success = theme.lightSuccess; + $vuetify.theme.themes.light.info = theme.lightInfo; + $vuetify.theme.themes.light.warning = theme.lightWarning; + $vuetify.theme.themes.light.error = theme.lightError; + + $vuetify.theme.themes.dark.primary = theme.darkPrimary; + $vuetify.theme.themes.dark.accent = theme.darkAccent; + $vuetify.theme.themes.dark.secondary = theme.darkSecondary; + $vuetify.theme.themes.dark.success = theme.darkSuccess; + $vuetify.theme.themes.dark.info = theme.darkInfo; + $vuetify.theme.themes.dark.warning = theme.darkWarning; + $vuetify.theme.themes.dark.error = theme.darkError; + } if ($config.useDark) { $vuetify.theme.dark = true; diff --git a/mealie/core/settings/settings.py b/mealie/core/settings/settings.py index bb8bd8cd9..08db0402d 100644 --- a/mealie/core/settings/settings.py +++ b/mealie/core/settings/settings.py @@ -3,6 +3,8 @@ from pathlib import Path from pydantic import BaseSettings, NoneStr, validator +from mealie.core.settings.themes import Theme + from .db_providers import AbstractDBProvider, db_provider_factory @@ -23,6 +25,8 @@ def determine_secrets(data_dir: Path, production: bool) -> str: class AppSettings(BaseSettings): + theme: Theme = Theme() + PRODUCTION: bool BASE_URL: str = "http://localhost:8080" """trailing slashes are trimmed (ex. `http://localhost:8080/` becomes ``http://localhost:8080`)""" diff --git a/mealie/core/settings/themes.py b/mealie/core/settings/themes.py new file mode 100644 index 000000000..e2fc8113d --- /dev/null +++ b/mealie/core/settings/themes.py @@ -0,0 +1,22 @@ +from pydantic import BaseSettings + + +class Theme(BaseSettings): + light_primary: str = "#E58325" + light_accent: str = "#007A99" + light_secondary: str = "#973542" + light_success: str = "#43A047" + light_info: str = "#1976D2" + light_warning: str = "#FF6D00" + light_error: str = "#EF5350" + + dark_primary: str = "#E58325" + dark_accent: str = "#007A99" + dark_secondary: str = "#973542" + dark_success: str = "#43A047" + dark_info: str = "#1976D2" + dark_warning: str = "#FF6D00" + dark_error: str = "#EF5350" + + class Config: + env_prefix = "theme_" diff --git a/mealie/routes/app/app_about.py b/mealie/routes/app/app_about.py index 87320e28d..750a23eea 100644 --- a/mealie/routes/app/app_about.py +++ b/mealie/routes/app/app_about.py @@ -1,8 +1,8 @@ -from fastapi import APIRouter +from fastapi import APIRouter, Response from mealie.core.config import get_app_settings from mealie.core.settings.static import APP_VERSION -from mealie.schema.admin.about import AppInfo +from mealie.schema.admin.about import AppInfo, AppTheme router = APIRouter(prefix="/about") @@ -18,3 +18,12 @@ def get_app_info(): production=settings.PRODUCTION, allow_signup=settings.ALLOW_SIGNUP, ) + + +@router.get("/theme", response_model=AppTheme) +def get_app_theme(resp: Response): + """Get's the current theme settings""" + settings = get_app_settings() + + resp.headers["Cache-Control"] = "public, max-age=604800" + return AppTheme(**settings.theme.dict()) diff --git a/mealie/schema/admin/about.py b/mealie/schema/admin/about.py index 68b644f7e..6a859cb7a 100644 --- a/mealie/schema/admin/about.py +++ b/mealie/schema/admin/about.py @@ -16,6 +16,24 @@ class AppInfo(MealieModel): allow_signup: bool +class AppTheme(MealieModel): + light_primary: str = "#E58325" + light_accent: str = "#007A99" + light_secondary: str = "#973542" + light_success: str = "#43A047" + light_info: str = "#1976D2" + light_warning: str = "#FF6D00" + light_error: str = "#EF5350" + + dark_primary: str = "#E58325" + dark_accent: str = "#007A99" + dark_secondary: str = "#973542" + dark_success: str = "#43A047" + dark_info: str = "#1976D2" + dark_warning: str = "#FF6D00" + dark_error: str = "#EF5350" + + class AdminAboutInfo(AppInfo): versionLatest: str api_port: int