diff --git a/docs/configuration.md b/docs/configuration.md index 5323671..43fb192 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -389,10 +389,12 @@ Example: ```yaml theme: + # This will be the default theme background-color: 100 20 10 primary-color: 40 90 40 contrast-multiplier: 1.1 + disable-picker: false presets: gruvbox-dark: background-color: 0 0 16 @@ -421,6 +423,7 @@ If you don't want to spend time configuring your own theme, there are [several a | contrast-multiplier | number | no | 1 | | text-saturation-multiplier | number | no | 1 | | custom-css-file | string | no | | +| disable-picker | bool | false | | | presets | object | no | | #### `light` @@ -466,8 +469,11 @@ theme: > > In addition, you can also use the `css-class` property which is available on every widget to set custom class names for individual widgets. +#### `disable-picker` +When set to `true` hides the theme picker and disables the abiltity to switch between themes. All users who previously picked a non-default theme will be switched over to the default theme. + #### `presets` -Define additional theme presets that can be selected from the theme switcher on the page. For each preset, you can specify the same properties as for the default theme, such as `background-color`, `primary-color`, `positive-color`, `negative-color`, `contrast-multiplier`, etc., except for the `custom-css-file` property. +Define additional theme presets that can be selected from the theme picker on the page. For each preset, you can specify the same properties as for the default theme, such as `background-color`, `primary-color`, `positive-color`, `negative-color`, `contrast-multiplier`, etc., except for the `custom-css-file` property. Example: diff --git a/internal/glance/config.go b/internal/glance/config.go index 84714d0..d4d6af0 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -47,8 +47,10 @@ type config struct { Theme struct { themeProperties `yaml:",inline"` - CustomCSSFile string `yaml:"custom-css-file"` - Presets orderedYAMLMap[string, *themeProperties] `yaml:"presets"` + CustomCSSFile string `yaml:"custom-css-file"` + + DisablePicker bool `yaml:"disable-picker"` + Presets orderedYAMLMap[string, *themeProperties] `yaml:"presets"` } `yaml:"theme"` Branding struct { diff --git a/internal/glance/glance.go b/internal/glance/glance.go index 2980f45..28771fa 100644 --- a/internal/glance/glance.go +++ b/internal/glance/glance.go @@ -101,35 +101,37 @@ func newApplication(c *config) (*application, error) { // Init themes // - themeKeys := make([]string, 0, 2) - themeProps := make([]*themeProperties, 0, 2) + if !config.Theme.DisablePicker { + themeKeys := make([]string, 0, 2) + themeProps := make([]*themeProperties, 0, 2) - defaultDarkTheme, ok := config.Theme.Presets.Get("default-dark") - if ok && !config.Theme.SameAs(defaultDarkTheme) || !config.Theme.SameAs(&themeProperties{}) { - themeKeys = append(themeKeys, "default-dark") - themeProps = append(themeProps, &themeProperties{}) - } + defaultDarkTheme, ok := config.Theme.Presets.Get("default-dark") + if ok && !config.Theme.SameAs(defaultDarkTheme) || !config.Theme.SameAs(&themeProperties{}) { + themeKeys = append(themeKeys, "default-dark") + themeProps = append(themeProps, &themeProperties{}) + } - themeKeys = append(themeKeys, "default-light") - themeProps = append(themeProps, &themeProperties{ - Light: true, - BackgroundColor: &hslColorField{240, 13, 95}, - PrimaryColor: &hslColorField{230, 100, 30}, - NegativeColor: &hslColorField{0, 70, 50}, - ContrastMultiplier: 1.3, - TextSaturationMultiplier: 0.5, - }) + themeKeys = append(themeKeys, "default-light") + themeProps = append(themeProps, &themeProperties{ + Light: true, + BackgroundColor: &hslColorField{240, 13, 95}, + PrimaryColor: &hslColorField{230, 100, 30}, + NegativeColor: &hslColorField{0, 70, 50}, + ContrastMultiplier: 1.3, + TextSaturationMultiplier: 0.5, + }) - themePresets, err := newOrderedYAMLMap(themeKeys, themeProps) - if err != nil { - return nil, fmt.Errorf("creating theme presets: %v", err) - } - config.Theme.Presets = *themePresets.Merge(&config.Theme.Presets) + themePresets, err := newOrderedYAMLMap(themeKeys, themeProps) + if err != nil { + return nil, fmt.Errorf("creating theme presets: %v", err) + } + config.Theme.Presets = *themePresets.Merge(&config.Theme.Presets) - for key, properties := range config.Theme.Presets.Items() { - properties.Key = key - if err := properties.init(); err != nil { - return nil, fmt.Errorf("initializing preset theme %s: %v", key, err) + for key, properties := range config.Theme.Presets.Items() { + properties.Key = key + if err := properties.init(); err != nil { + return nil, fmt.Errorf("initializing preset theme %s: %v", key, err) + } } } @@ -288,11 +290,13 @@ type templateData struct { func (a *application) populateTemplateRequestData(data *templateRequestData, r *http.Request) { theme := &a.Config.Theme.themeProperties - selectedTheme, err := r.Cookie("theme") - if err == nil { - preset, exists := a.Config.Theme.Presets.Get(selectedTheme.Value) - if exists { - theme = preset + if !a.Config.Theme.DisablePicker { + selectedTheme, err := r.Cookie("theme") + if err == nil { + preset, exists := a.Config.Theme.Presets.Get(selectedTheme.Value) + if exists { + theme = preset + } } } @@ -436,7 +440,11 @@ func (a *application) server() (func() error, func() error) { mux.HandleFunc("GET /{page}", a.handlePageRequest) mux.HandleFunc("GET /api/pages/{page}/content/{$}", a.handlePageContentRequest) - mux.HandleFunc("POST /api/set-theme/{key}", a.handleThemeChangeRequest) + + if !a.Config.Theme.DisablePicker { + mux.HandleFunc("POST /api/set-theme/{key}", a.handleThemeChangeRequest) + } + mux.HandleFunc("/api/widgets/{widget}/{path...}", a.handleWidgetRequest) mux.HandleFunc("GET /api/healthz", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) diff --git a/internal/glance/static/js/page.js b/internal/glance/static/js/page.js index 9ef639a..5ee6d16 100644 --- a/internal/glance/static/js/page.js +++ b/internal/glance/static/js/page.js @@ -689,12 +689,15 @@ async function changeTheme(key, onChanged) { setTimeout(() => { tempStyle.remove(); }, 10); } -function initThemeSwitcher() { +function initThemePicker() { + const themeChoicesInMobileNav = find(".mobile-navigation .theme-choices"); + if (!themeChoicesInMobileNav) return; + const themeChoicesInHeader = find(".header-container .theme-choices"); if (themeChoicesInHeader) { themeChoicesInHeader.replaceWith( - find(".mobile-navigation .theme-choices").cloneNode(true) + themeChoicesInMobileNav.cloneNode(true) ); } @@ -739,7 +742,7 @@ function initThemeSwitcher() { } async function setupPage() { - initThemeSwitcher(); + initThemePicker(); const pageElement = document.getElementById("page"); const pageContentElement = document.getElementById("page-content"); diff --git a/internal/glance/templates/page.html b/internal/glance/templates/page.html index 7dbf812..0f83183 100644 --- a/internal/glance/templates/page.html +++ b/internal/glance/templates/page.html @@ -33,6 +33,7 @@ + {{ if not .App.Config.Theme.DisablePicker }}
{{ .Request.Theme.PreviewHTML }} @@ -41,6 +42,7 @@
+ {{ end }} {{- if .App.RequiresAuth }} @@ -66,6 +68,7 @@
+ {{ if not .App.Config.Theme.DisablePicker }}
@@ -87,6 +90,7 @@
+ {{ end }} {{ if .App.RequiresAuth }}