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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +6 -0
- data/VERSION +1 -1
- data/app/application.css +3 -2
- data/app/application_vars.css.erb +10 -2
- data/app/layout.css +39 -0
- data/app/layout.html.erb +46 -0
- data/app/layout_vars.css.erb +9 -5
- data/lib/ultra_settings/application_view.rb +4 -3
- data/lib/ultra_settings/web_view.rb +9 -6
- data/lib/ultra_settings.rb +9 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 013b301669011dc685fc7016e1b66c12a6c8890f7b8dc9ba5bdb63c188eee191
|
|
4
|
+
data.tar.gz: 1d558756ea2014cea76c2c98747ae0dd760e32a9526cb6548d61e93ea0e11e1b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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>
|
data/app/layout_vars.css.erb
CHANGED
|
@@ -19,15 +19,19 @@
|
|
|
19
19
|
|
|
20
20
|
<% if color_scheme == :system %>
|
|
21
21
|
@media (prefers-color-scheme: dark) {
|
|
22
|
-
|
|
23
|
-
<%
|
|
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: #
|
|
29
|
-
--text-secondary: #
|
|
30
|
-
--text-tertiary: #
|
|
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`.
|
|
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 =
|
|
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}"
|
data/lib/ultra_settings.rb
CHANGED
|
@@ -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
|
|
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
|
|