super_settings 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5417df66afb91b92e9142075a083883d6884a5f148858b43738cafb4bbe5aea3
4
- data.tar.gz: 7156046f2de10818424ff1997a1aea922ea5c67ebea1c0fe2ce8ffbb5f8a9746
3
+ metadata.gz: 3c33c68388f12bb6216f928e778f5a4965bf11f263bc315f0a9ce9261f9d4637
4
+ data.tar.gz: fc7e9bd62a5412843c0da1a2accf93812869ae85cf91c8b7accd0eb496c9cf00
5
5
  SHA512:
6
- metadata.gz: a8fd1761f7cf0eeee7b30d06ea1dc7b766dde492c3b8786fb549469ee76e1d81321696ea1d8bef1a272896be6992ab5af598cf521e4c91090602f5fe809de146
7
- data.tar.gz: fc346701a55ad717e806d234780df064aebe15d981e1e5da65c4d435bcb6b8b13d6b5ac240d654e827e167ebd083dbb8e4319831bb7aa09aba94b44ac27b8f7f
6
+ metadata.gz: d85f6b31e1757e36fbfe6486851ee2ccfdf10b13bca742ed90910898761c2215ca053ee2a91ad204b65913d765b66084b03e802544985c3d3c263d692c54480d
7
+ data.tar.gz: 17a61ebac8696d0d2b1ca09229b0826d8885853e858f3ebcb2956cad00d56cf35f9e0928afc4c4e0987d270be3b9b23ab52cf18c91c91874281e3ac2239e81ad
data/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 2.6.0
8
+
9
+ ### Added
10
+
11
+ - Added `SuperSettings::Application#dark_mode_selector` configuration option that allows you to specify a CSS selector that sets dark mode when it matches an element in the page. This is an alternative to using the `color_scheme` option and allows for more flexible control of when dark mode is enabled.
12
+
7
13
  ## 2.5.0
8
14
 
9
15
  ### Added
data/README.md CHANGED
@@ -308,6 +308,13 @@ SuperSettings.configure do |config|
308
308
  # Set the color scheme to use for the Web UI. Options are :light (default), :dark, or :system.
309
309
  config.controller.color_scheme = :dark
310
310
 
311
+ # Set a CSS selector for enabling dark mode. When the selector matches an element on the page,
312
+ # dark mode styles will be applied. A theme toggle button will also be rendered in the header
313
+ # allowing users to switch between light and dark modes (persisted via localStorage).
314
+ # This is an alternative to the color_scheme option. If neither color_scheme nor dark_mode_selector
315
+ # is set, it defaults to "[data-theme=dark]" which enables the toggle automatically.
316
+ config.controller.dark_mode_selector = "[data-theme=dark]"
317
+
311
318
  # Add additional code to the controller. In this case we are adding code to ensure only
312
319
  # admins can access the functionality and changing the layout to use one defined by the application.
313
320
  config.controller.enhance do
@@ -464,12 +471,6 @@ This will work out of the box with the defaults for the storage engines when run
464
471
  - `S3_URL` - `s3://accesskey:secretkey@region-1/settings/settings.json` (the S3 endpoint will be set to `http://localhost:9000`)
465
472
  - `MONGODB_URL` - `mongodb://localhost:27017/super_settings`
466
473
 
467
- Finally, you can run the application in dark mode by setting the `COLOR_SCHEME` environment variable.
468
-
469
- ```bash
470
- COLOR_SCHEME=dark bundle exec rackup
471
- ```
472
-
473
474
  ## License
474
475
 
475
476
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.5.0
1
+ 2.6.0
@@ -29,6 +29,7 @@ module SuperSettings
29
29
  application_dir = File.expand_path(File.join("..", "..", "..", "lib", "super_settings", "application"), __dir__)
30
30
  erb = ERB.new(File.read(File.join(application_dir, "layout_vars.css.erb")))
31
31
  color_scheme = SuperSettings.configuration.controller.color_scheme
32
+ dark_mode_selector = SuperSettings.configuration.controller.dark_mode_selector
32
33
  erb.result(binding).html_safe
33
34
  end
34
35
  end
@@ -222,6 +222,14 @@ module SuperSettings
222
222
  @color_scheme if defined?(@color_scheme)
223
223
  end
224
224
 
225
+ # A CSS selector that sets dark mode when it matches an element in the page.
226
+ # This is an alternative to using the color_scheme option.
227
+ #
228
+ # @return [String, nil]
229
+ def dark_mode_selector
230
+ @dark_mode_selector if defined?(@dark_mode_selector)
231
+ end
232
+
225
233
  # Whether the application is in read-only mode.
226
234
  #
227
235
  # @return [Boolean]
@@ -8,6 +8,18 @@
8
8
  <meta name="format-detection" content="telephone=no email=no date=no address=no">
9
9
  <meta name="robots" content="noindex, nofollow">
10
10
  <meta name="referrer" content="no-referrer-when-downgrade">
11
+ <% if dark_mode_selector %>
12
+ <script>
13
+ (function() {
14
+ try {
15
+ if (localStorage.getItem("super_settings_theme") === "dark") {
16
+ document.documentElement.setAttribute("data-theme", "dark");
17
+ }
18
+ } catch (e) {
19
+ }
20
+ })();
21
+ </script>
22
+ <% end %>
11
23
  <%= layout_style_tag %>
12
24
  <%= add_to_head %>
13
25
  </head>
@@ -16,6 +28,24 @@
16
28
  <header class="super-settings-page-header">
17
29
  <div class="super-settings-page-header-inner">
18
30
  <%= application_header %>
31
+ <% if dark_mode_selector %>
32
+ <button type="button" class="super-settings-theme-toggle" id="super-settings-theme-toggle" aria-label="Toggle dark mode">
33
+ <svg class="super-settings-theme-icon super-settings-theme-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
34
+ <circle cx="12" cy="12" r="4"></circle>
35
+ <path d="M12 2v2"></path>
36
+ <path d="M12 20v2"></path>
37
+ <path d="m4.93 4.93 1.41 1.41"></path>
38
+ <path d="m17.66 17.66 1.41 1.41"></path>
39
+ <path d="M2 12h2"></path>
40
+ <path d="M20 12h2"></path>
41
+ <path d="m6.34 17.66-1.41 1.41"></path>
42
+ <path d="m19.07 4.93-1.41 1.41"></path>
43
+ </svg>
44
+ <svg class="super-settings-theme-icon super-settings-theme-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
45
+ <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
46
+ </svg>
47
+ </button>
48
+ <% end %>
19
49
  </div>
20
50
  </header>
21
51
 
@@ -72,5 +102,31 @@
72
102
  </details>
73
103
  </footer>
74
104
  <% end %>
105
+ <% if dark_mode_selector %>
106
+ <script>
107
+ (function() {
108
+ var toggle = document.getElementById("super-settings-theme-toggle");
109
+ if (!toggle) return;
110
+
111
+ var html = document.documentElement;
112
+ toggle.addEventListener("click", function() {
113
+ var isDark = html.getAttribute("data-theme") === "dark";
114
+ if (isDark) {
115
+ html.removeAttribute("data-theme");
116
+ try {
117
+ localStorage.removeItem("super_settings_theme");
118
+ } catch (e) {
119
+ }
120
+ } else {
121
+ html.setAttribute("data-theme", "dark");
122
+ try {
123
+ localStorage.setItem("super_settings_theme", "dark");
124
+ } catch (e) {
125
+ }
126
+ }
127
+ });
128
+ })();
129
+ </script>
130
+ <% end %>
75
131
  </body>
76
132
  </html>
@@ -112,6 +112,43 @@ a:visited {
112
112
  justify-content: flex-end;
113
113
  }
114
114
 
115
+ .super-settings-theme-toggle {
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ width: 36px;
120
+ height: 36px;
121
+ border: 1px solid transparent;
122
+ border-radius: 8px;
123
+ background: transparent;
124
+ color: #9ca3af;
125
+ cursor: pointer;
126
+ flex-shrink: 0;
127
+ transition: color 0.2s, border-color 0.2s;
128
+ }
129
+
130
+ .super-settings-theme-toggle:hover {
131
+ color: var(--link-color);
132
+ border-color: var(--link-color);
133
+ }
134
+
135
+ .super-settings-theme-icon {
136
+ width: 18px;
137
+ height: 18px;
138
+ }
139
+
140
+ .super-settings-theme-icon-moon {
141
+ display: none;
142
+ }
143
+
144
+ [data-theme="dark"] .super-settings-theme-icon-sun {
145
+ display: none;
146
+ }
147
+
148
+ [data-theme="dark"] .super-settings-theme-icon-moon {
149
+ display: block;
150
+ }
151
+
115
152
  /* ══════════════════════════════════════════
116
153
  LANGUAGE MENU (in footer)
117
154
  ══════════════════════════════════════════ */
@@ -13,7 +13,11 @@
13
13
  <% end %>
14
14
  <% if color_scheme == :system || color_scheme == :dark %>
15
15
  :root {
16
- --text-color: #e5e7eb;
16
+ <% elsif dark_mode_selector %>
17
+ :root<%= dark_mode_selector %> {
18
+ <% end %>
19
+ <% if color_scheme == :system || color_scheme == :dark || dark_mode_selector %>
20
+ --text-color: #eef0f8;
17
21
  --background-color: #1a1d23;
18
22
  --header-background-color: #21252b;
19
23
  --link-color: #2dd4bf;
@@ -71,8 +71,10 @@
71
71
 
72
72
  <% if color_scheme == :system %>
73
73
  @media (prefers-color-scheme: dark) {
74
+ <% elsif dark_mode_selector %>
75
+ <%= dark_mode_selector %> {
74
76
  <% end %>
75
- <% if color_scheme == :system || color_scheme == :dark %>
77
+ <% if color_scheme == :system || color_scheme == :dark || dark_mode_selector %>
76
78
  .super-settings {
77
79
  /* Canvas */
78
80
  --bg-page: #1a1d23;
@@ -128,6 +130,6 @@
128
130
  --icon-disabled-color: #4b5563;
129
131
  }
130
132
  <% end %>
131
- <% if color_scheme == :system %>
133
+ <% if color_scheme == :system || dark_mode_selector %>
132
134
  }
133
135
  <% end %>
@@ -8,14 +8,16 @@ module SuperSettings
8
8
  include Helper
9
9
 
10
10
  # @param layout [String, Symbol] path to an ERB template to use as the layout around the application UI. You can
11
- # pass the symbol +:default+ to use the default layout that ships with the gem.
11
+ # pass the symbol +:default+ to use the default layout that ships with the gem.
12
12
  # @param add_to_head [String] HTML code to add to the <head> element on the page.
13
13
  # @param api_base_url [String] the base URL for the REST API.
14
14
  # @param color_scheme [Symbol] whether to use dark mode for the application UI. If +nil+, the user's system
15
- # preference will be used.
15
+ # preference will be used.
16
+ # @param dark_mode_selector [String] a CSS selector that sets dark mode when it matches an element in the page.
17
+ # This is an alternative to using the color_scheme option.
16
18
  # @param read_only [Boolean] whether to render the application in read-only mode (edit controls hidden).
17
19
  # @param locale [String] the locale code for translations (default: "en").
18
- def initialize(layout: nil, add_to_head: nil, api_base_url: nil, color_scheme: nil, read_only: false, locale: nil)
20
+ def initialize(layout: nil, add_to_head: nil, api_base_url: nil, color_scheme: nil, dark_mode_selector: nil, read_only: false, locale: nil)
19
21
  if layout
20
22
  layout = File.expand_path(File.join("application", "layout.html.erb"), __dir__) if layout == :default
21
23
  @layout = ERB.new(File.read(layout)) if layout
@@ -27,6 +29,7 @@ module SuperSettings
27
29
 
28
30
  @api_base_url = api_base_url
29
31
  @color_scheme = color_scheme&.to_sym
32
+ @dark_mode_selector = dark_mode_selector
30
33
  @read_only = !!read_only
31
34
  @locale = locale || SuperSettings::MiniI18n::DEFAULT_LOCALE
32
35
  end
@@ -12,6 +12,8 @@ module SuperSettings
12
12
 
13
13
  # Configuration for the controller.
14
14
  class Controller
15
+ VALID_COLOR_SCHEMES = [:light, :dark, :system].freeze
16
+
15
17
  # @api private
16
18
  attr_reader :enhancement
17
19
 
@@ -25,12 +27,13 @@ module SuperSettings
25
27
  def initialize
26
28
  @superclass = nil
27
29
  @web_ui_enabled = true
28
- @color_scheme = false
30
+ @color_scheme = nil
29
31
  @changed_by_block = nil
30
32
  @enhancement = nil
31
33
  @application_name = nil
32
34
  @application_logo = nil
33
35
  @application_link = nil
36
+ @dark_mode_selector = nil
34
37
  end
35
38
 
36
39
  def superclass
@@ -41,10 +44,10 @@ module SuperSettings
41
44
  end
42
45
  end
43
46
 
44
- # Optinal name of the application displayed in the view.
47
+ # Optional name of the application displayed in the view.
45
48
  attr_accessor :application_name
46
49
 
47
- # Optional mage URL for the application logo.
50
+ # Optional image URL for the application logo.
48
51
  attr_accessor :application_logo
49
52
 
50
53
  # Optional URL for a link back to the rest of the application.
@@ -69,11 +72,30 @@ module SuperSettings
69
72
  end
70
73
 
71
74
  # Set dark mode for the web UI. Possible values are :light, :dark, or :system.
72
- # The default value is :light.
75
+ # When the value is not set (or is invalid), theme selection is left dynamic.
73
76
  attr_writer :color_scheme
74
77
 
78
+ # Return the configured color scheme.
79
+ #
80
+ # @return [Symbol, nil]
75
81
  def color_scheme
76
- (@color_scheme ||= :light).to_sym
82
+ scheme = @color_scheme&.to_sym
83
+ VALID_COLOR_SCHEMES.include?(scheme) ? scheme : nil
84
+ end
85
+
86
+ # Set a CSS selector that sets dark mode. This is an alternative to using the color_scheme
87
+ # option and can be used if you have a custom implementation for dark mode in your application.
88
+ # Dark mode will be enabled in the settings web UI when the selector matches an element in the page.
89
+ attr_accessor :dark_mode_selector
90
+
91
+ # Return the selector used to enable dark mode from host page state.
92
+ #
93
+ # @return [String, nil]
94
+ def resolved_dark_mode_selector
95
+ return @dark_mode_selector if @dark_mode_selector
96
+ return "[data-theme=dark]" if color_scheme.nil?
97
+
98
+ nil
77
99
  end
78
100
 
79
101
  # Enhance the controller. You can define methods or call controller class methods like
@@ -19,8 +19,13 @@ module SuperSettings
19
19
 
20
20
  # Render the HTML application for managing settings.
21
21
  def root
22
- html = SuperSettings::Application.new(read_only: super_settings_read_only?, locale: I18n.locale).render
23
- render html: html.html_safe, layout: true
22
+ application = SuperSettings::Application.new(
23
+ read_only: super_settings_read_only?,
24
+ locale: I18n.locale,
25
+ color_scheme: SuperSettings.configuration.controller.color_scheme,
26
+ dark_mode_selector: SuperSettings.configuration.controller.resolved_dark_mode_selector
27
+ )
28
+ render html: application.render.html_safe, layout: true
24
29
  end
25
30
 
26
31
  # API endpoint for getting active settings. See SuperSettings::RestAPI for details.
@@ -104,9 +104,9 @@ module SuperSettings
104
104
  # Subclasses can override this method to return the path to an ERB file to use as the layout
105
105
  # for the HTML application. The layout can use any of the methods defined in SuperSettings::Application::Helper.
106
106
  #
107
- # @return [String]
107
+ # @return [String, Symbol]
108
108
  def layout
109
- "layout.html.erb"
109
+ :default
110
110
  end
111
111
 
112
112
  # Subclasses can override this method to add custom HTML to the <head> element in the HTML application.
@@ -186,7 +186,15 @@ module SuperSettings
186
186
  if lang && SuperSettings::MiniI18n.available_locales.include?(lang)
187
187
  headers["set-cookie"] = "super_settings_locale=#{lang}; path=/; SameSite=Lax"
188
188
  end
189
- [200, headers, [Application.new(layout: :default, add_to_head: add_to_head(request), color_scheme: SuperSettings.configuration.controller.color_scheme, read_only: read_only, locale: locale).render]]
189
+ application = Application.new(
190
+ layout: layout,
191
+ add_to_head: add_to_head(request),
192
+ color_scheme: SuperSettings.configuration.controller.color_scheme,
193
+ dark_mode_selector: SuperSettings.configuration.controller.resolved_dark_mode_selector,
194
+ read_only: read_only,
195
+ locale: locale
196
+ )
197
+ [200, headers, [application.render]]
190
198
  end
191
199
 
192
200
  if [401, 403].include?(response.first)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: super_settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand