ultra_settings 2.9.1 → 2.10.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: 802faa3f09b5b24f1d0cad36e7014bf84f092b48e7b81fa0b6f73798fbd071ff
4
- data.tar.gz: 3dd890b1e59e1ae946edd1eda0a3b509386d6d50a30d269a437ae982b73bb7ba
3
+ metadata.gz: 013b301669011dc685fc7016e1b66c12a6c8890f7b8dc9ba5bdb63c188eee191
4
+ data.tar.gz: 1d558756ea2014cea76c2c98747ae0dd760e32a9526cb6548d61e93ea0e11e1b
5
5
  SHA512:
6
- metadata.gz: 0a1dd9d6c83b3999f8559a7b52c9c7195d106dfb5073e1f6366376a27c04a1e9bd27ef846e207b8041b7ad6b1863283959bf8c07d8cc8a90f1ef0178641e0948
7
- data.tar.gz: ddef9a41588c9aa97c4d8ad0da56e4e55089ea3a9e45d8edd3dcc8e9710fda83a156fcee36d9592a096497e0e24a2c32e255c0dafb52cf6d9771258abaef4b10
6
+ metadata.gz: 866378e50cdd9016084f5f6b1db66d97a32c3f9108c2ac44aaff59e7412a4980e439f254b6aed704d7f64ee955b9c33e23c4e698a5d179d2f072452fff37c1c2
7
+ data.tar.gz: f262427eb43bb6a78bcb034ef276e98de5517eeb77283022fcd25a40af947de4dc6a7c123c1c45a6067b21aa36beaeca086a04b46ca7bc14b0d6fbe4590520d6
data/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ 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.10.0
8
+
9
+ ### Added
10
+
11
+ - Added `dark_mode_selector` option to `UltraSettings::Application` to allow the web UI to automatically switch to dark mode based on a CSS selector in the host application.
12
+
13
+ ### Fixed
14
+
15
+ - Fixed configurations showing up multiple times in the web UI when the configuration class is reloaded in Rails development mode.
16
+
7
17
  ## 2.9.1
8
18
 
9
19
  ### Fixed
data/README.md CHANGED
@@ -453,6 +453,12 @@ You can specify the color scheme by setting by providing the `color_scheme` opti
453
453
  UltraSettings::ApplicationView.new(color_scheme: :dark)
454
454
  ```
455
455
 
456
+ If your application already controls dark mode with a CSS selector (for example, a `data` attribute on the `<html>` element), you can pass a `dark_mode_selector` instead of a fixed color scheme. The settings UI will automatically switch to dark mode whenever the selector matches:
457
+
458
+ ```ruby
459
+ UltraSettings::ApplicationView.new(dark_mode_selector: "[data-theme=dark]")
460
+ ```
461
+
456
462
  You can specify the language to render the application in with the `locale` option to the `UltraSettings::ApplicationView` constructor. The default language is English but it can be changed to any language that has a corresponding JSON file in the `app/locales` directory.
457
463
 
458
464
  ```ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.9.1
1
+ 2.10.0
data/app/application.css CHANGED
@@ -1052,16 +1052,17 @@ input[type="number"].ultra-settings-ss-input::-webkit-outer-spin-button {
1052
1052
 
1053
1053
  .ultra-settings-ss-btn-cancel {
1054
1054
  background: transparent;
1055
- color: var(--text-secondary);
1055
+ color: var(--btn-secondary-text, var(--text-secondary));
1056
1056
  }
1057
1057
 
1058
1058
  .ultra-settings-ss-btn-cancel:hover {
1059
1059
  background: var(--bg-code);
1060
+ color: var(--btn-secondary-hover-text, var(--text-primary));
1060
1061
  }
1061
1062
 
1062
1063
  .ultra-settings-ss-btn-save {
1063
1064
  background: var(--accent);
1064
- color: #fff;
1065
+ color: var(--btn-primary-text, #fff);
1065
1066
  border-color: var(--accent);
1066
1067
  }
1067
1068
 
@@ -24,6 +24,9 @@
24
24
  --accent-light: rgba(13, 148, 136, 0.06);
25
25
  --accent-lighter: rgba(13, 148, 136, 0.03);
26
26
  --accent-glow: rgba(13, 148, 136, 0.12);
27
+ --btn-primary-text: #ffffff;
28
+ --btn-secondary-text: #4b5563;
29
+ --btn-secondary-hover-text: #111827;
27
30
 
28
31
  /* Source palette */
29
32
  --src-env: #2563eb;
@@ -73,8 +76,10 @@
73
76
 
74
77
  <% if color_scheme == :system %>
75
78
  @media (prefers-color-scheme: dark) {
79
+ <% elsif dark_mode_selector %>
80
+ <%= dark_mode_selector %> {
76
81
  <% end %>
77
- <% if color_scheme == :system || color_scheme == :dark %>
82
+ <% if color_scheme == :system || color_scheme == :dark || dark_mode_selector %>
78
83
  .ultra-settings, .ultra-settings-block {
79
84
  --font-ui: system-ui, -apple-system, sans-serif;
80
85
  --font-mono: "SF Mono", Menlo, Consolas, monospace;
@@ -100,6 +105,9 @@
100
105
  --accent-light: rgba(20, 184, 166, 0.10);
101
106
  --accent-lighter: rgba(20, 184, 166, 0.05);
102
107
  --accent-glow: rgba(20, 184, 166, 0.15);
108
+ --btn-primary-text: #04211d;
109
+ --btn-secondary-text: #c8cede;
110
+ --btn-secondary-hover-text: #e8ecf8;
103
111
 
104
112
  /* Source palette */
105
113
  --src-env: #60a5fa;
@@ -146,6 +154,6 @@
146
154
  --border-source-row: rgba(255,255,255,0.04);
147
155
  }
148
156
  <% end %>
149
- <% if color_scheme == :system %>
157
+ <% if color_scheme == :system || dark_mode_selector %>
150
158
  }
151
159
  <% end %>
data/app/layout.css CHANGED
@@ -84,6 +84,45 @@ body {
84
84
  justify-content: flex-end;
85
85
  }
86
86
 
87
+ /* ── Theme toggle ── */
88
+
89
+ .ultra-settings-theme-toggle {
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ width: 36px;
94
+ height: 36px;
95
+ border: 1px solid transparent;
96
+ border-radius: 8px;
97
+ background: transparent;
98
+ color: var(--text-tertiary, #9ca3af);
99
+ cursor: pointer;
100
+ flex-shrink: 0;
101
+ transition: color 0.2s, border-color 0.2s;
102
+ }
103
+
104
+ .ultra-settings-theme-toggle:hover {
105
+ color: var(--accent, #0d9488);
106
+ border-color: var(--accent, #0d9488);
107
+ }
108
+
109
+ .ultra-settings-theme-icon {
110
+ width: 18px;
111
+ height: 18px;
112
+ }
113
+
114
+ .ultra-settings-theme-icon-moon {
115
+ display: none;
116
+ }
117
+
118
+ [data-theme="dark"] .ultra-settings-theme-icon-sun {
119
+ display: none;
120
+ }
121
+
122
+ [data-theme="dark"] .ultra-settings-theme-icon-moon {
123
+ display: block;
124
+ }
125
+
87
126
  @media (max-width: 640px) {
88
127
  .ultra-settings-page-header-inner {
89
128
  padding: 16px;
data/app/layout.html.erb CHANGED
@@ -6,6 +6,15 @@
6
6
  <meta charset="utf-8">
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1">
8
8
  <meta name="format-detection" content="telephone=no email=no date=no address=no">
9
+ <% if @dark_mode_selector %>
10
+ <script>
11
+ (function() {
12
+ if (localStorage.getItem("ultra_settings_theme") === "dark") {
13
+ document.documentElement.setAttribute("data-theme", "dark");
14
+ }
15
+ })();
16
+ </script>
17
+ <% end %>
9
18
  <style type="text/css">
10
19
  <%= layout_css %>
11
20
  </style>
@@ -25,6 +34,24 @@
25
34
  <p class="ultra-settings-page-header-subtitle"><%= t("page.brand_subtitle") %></p>
26
35
  </div>
27
36
  </div>
37
+ <% if @dark_mode_selector %>
38
+ <button type="button" class="ultra-settings-theme-toggle" id="ultra-settings-theme-toggle" aria-label="Toggle dark mode">
39
+ <svg class="ultra-settings-theme-icon ultra-settings-theme-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
40
+ <circle cx="12" cy="12" r="4"></circle>
41
+ <path d="M12 2v2"></path>
42
+ <path d="M12 20v2"></path>
43
+ <path d="m4.93 4.93 1.41 1.41"></path>
44
+ <path d="m17.66 17.66 1.41 1.41"></path>
45
+ <path d="M2 12h2"></path>
46
+ <path d="M20 12h2"></path>
47
+ <path d="m6.34 17.66-1.41 1.41"></path>
48
+ <path d="m19.07 4.93-1.41 1.41"></path>
49
+ </svg>
50
+ <svg class="ultra-settings-theme-icon ultra-settings-theme-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
51
+ <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
52
+ </svg>
53
+ </button>
54
+ <% end %>
28
55
  </div>
29
56
  </header>
30
57
  <main class="ultra-settings-page-content">
@@ -79,5 +106,24 @@
79
106
  </details>
80
107
  </footer>
81
108
  <% end %>
109
+ <% if @dark_mode_selector %>
110
+ <script>
111
+ (function() {
112
+ var toggle = document.getElementById("ultra-settings-theme-toggle");
113
+ if (!toggle) return;
114
+ var html = document.documentElement;
115
+ toggle.addEventListener("click", function() {
116
+ var isDark = html.getAttribute("data-theme") === "dark";
117
+ if (isDark) {
118
+ html.removeAttribute("data-theme");
119
+ localStorage.removeItem("ultra_settings_theme");
120
+ } else {
121
+ html.setAttribute("data-theme", "dark");
122
+ localStorage.setItem("ultra_settings_theme", "dark");
123
+ }
124
+ });
125
+ })();
126
+ </script>
127
+ <% end %>
82
128
  </body>
83
129
  </html>
@@ -19,15 +19,19 @@
19
19
 
20
20
  <% if color_scheme == :system %>
21
21
  @media (prefers-color-scheme: dark) {
22
- <% end %>
23
- <% if color_scheme == :system || color_scheme == :dark %>
22
+ :root {
23
+ <% elsif dark_mode_selector %>
24
+ :root<%= dark_mode_selector %> {
25
+ <% elsif color_scheme == :dark %>
24
26
  :root {
27
+ <% end %>
28
+ <% if color_scheme == :system || color_scheme == :dark || dark_mode_selector %>
25
29
  --font-ui: system-ui, -apple-system, sans-serif;
26
30
  --font-mono: "SF Mono", Menlo, Consolas, monospace;
27
31
  --bg-page: #0f1117;
28
- --text-primary: #e4e6f0;
29
- --text-secondary: #9ba1b5;
30
- --text-tertiary: #5c6178;
32
+ --text-primary: #eef0f8;
33
+ --text-secondary: #adb3c8;
34
+ --text-tertiary: #6e7490;
31
35
  --accent: #14b8a6;
32
36
  --border-light: #2a2d3a;
33
37
  --bg-card: #1a1c26;
@@ -18,9 +18,10 @@ module UltraSettings
18
18
  # Initialize the application view with a color scheme.
19
19
  #
20
20
  # @param color_scheme [Symbol] The color scheme to use (:light, :dark, or :system).
21
+ # @param dark_mode_selector [String, nil] The CSS selector for dark mode.
21
22
  # @param locale [String] The locale code for translations.
22
- def initialize(color_scheme: :light, locale: UltraSettings::MiniI18n::DEFAULT_LOCALE)
23
- @css = application_css(color_scheme)
23
+ def initialize(color_scheme: :light, dark_mode_selector: nil, locale: UltraSettings::MiniI18n::DEFAULT_LOCALE)
24
+ @css = application_css(color_scheme, dark_mode_selector)
24
25
  @css = @css.html_safe if @css.respond_to?(:html_safe)
25
26
  @locale = locale
26
27
  end
@@ -74,7 +75,7 @@ module UltraSettings
74
75
  ViewHelper.read_app_file("application.js")
75
76
  end
76
77
 
77
- def application_css(color_scheme)
78
+ def application_css(color_scheme, dark_mode_selector)
78
79
  vars = ViewHelper.erb_template("application_vars.css.erb").result(binding).strip
79
80
  css = ViewHelper.read_app_file("application.css").strip
80
81
  "#{vars}\n#{css}"
@@ -9,12 +9,14 @@ module UltraSettings
9
9
 
10
10
  # Initialize a new WebView with the specified color scheme.
11
11
  #
12
- # @param color_scheme [Symbol] The color scheme to use in the UI. This can be `:light`,
13
- # `:dark`, or `:system`. The default is `:light`.
12
+ # @param color_scheme [Symbol, nil] The color scheme to use in the UI. This can be `:light`,
13
+ # `:dark`, or `:system`. When `nil`, a toggle control is rendered and
14
+ # `[data-theme=dark]` is used as the dark mode CSS selector.
14
15
  def initialize(color_scheme: :light)
15
- @color_scheme = (color_scheme || :light).to_sym
16
+ @color_scheme = color_scheme&.to_sym
17
+ @dark_mode_selector = @color_scheme.nil? ? "[data-theme=dark]" : nil
16
18
  @layout_template = ViewHelper.erb_template("layout.html.erb")
17
- @layout_css = scheme_layout_css(@color_scheme)
19
+ @layout_css = scheme_layout_css(@color_scheme, @dark_mode_selector)
18
20
  end
19
21
 
20
22
  # Render the complete settings page HTML.
@@ -34,7 +36,8 @@ module UltraSettings
34
36
  # @return [String] The HTML content for the settings.
35
37
  def content
36
38
  UltraSettings::ApplicationView.new(
37
- color_scheme: @color_scheme,
39
+ color_scheme: @color_scheme || :light,
40
+ dark_mode_selector: @dark_mode_selector,
38
41
  locale: @locale || UltraSettings::MiniI18n::DEFAULT_LOCALE
39
42
  ).render
40
43
  end
@@ -56,7 +59,7 @@ module UltraSettings
56
59
 
57
60
  private
58
61
 
59
- def scheme_layout_css(color_scheme)
62
+ def scheme_layout_css(color_scheme, dark_mode_selector)
60
63
  vars = ViewHelper.erb_template("layout_vars.css.erb").result(binding)
61
64
  css = ViewHelper.read_app_file("layout.css")
62
65
  "#{vars}\n#{css}"
@@ -299,7 +299,15 @@ module UltraSettings
299
299
  __load_config__(name, class_name)
300
300
  end
301
301
 
302
- config_classes = ObjectSpace.each_object(Class).select { |klass| klass < Configuration }
302
+ config_classes = ObjectSpace.each_object(Class).select do |klass|
303
+ next false unless klass < Configuration
304
+ next false if klass.name.nil?
305
+ begin
306
+ constantize(klass.name).equal?(klass)
307
+ rescue NameError
308
+ false
309
+ end
310
+ end
303
311
  config_classes.collect(&:instance)
304
312
  end
305
313
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ultra_settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.1
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand