super_settings 2.4.3 → 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 +4 -4
- data/AGENTS.md +27 -0
- data/ARCHITECTURE.md +232 -0
- data/CHANGELOG.md +29 -0
- data/README.md +56 -6
- data/VERSION +1 -1
- data/app/helpers/super_settings/settings_helper.rb +5 -11
- data/app/locales/ar.json +44 -0
- data/app/locales/cs.json +44 -0
- data/app/locales/da.json +44 -0
- data/app/locales/de.json +44 -0
- data/app/locales/el.json +44 -0
- data/app/locales/en.json +55 -0
- data/app/locales/es.json +44 -0
- data/app/locales/fa.json +44 -0
- data/app/locales/fr.json +44 -0
- data/app/locales/gd.json +44 -0
- data/app/locales/he.json +44 -0
- data/app/locales/hi.json +44 -0
- data/app/locales/it.json +44 -0
- data/app/locales/ja.json +44 -0
- data/app/locales/ko.json +44 -0
- data/app/locales/lt.json +44 -0
- data/app/locales/nb.json +44 -0
- data/app/locales/nl.json +44 -0
- data/app/locales/pl.json +44 -0
- data/app/locales/pt-br.json +44 -0
- data/app/locales/pt.json +44 -0
- data/app/locales/ru.json +44 -0
- data/app/locales/sv.json +44 -0
- data/app/locales/ta.json +44 -0
- data/app/locales/tr.json +44 -0
- data/app/locales/uk.json +44 -0
- data/app/locales/ur.json +44 -0
- data/app/locales/vi.json +44 -0
- data/app/locales/zh-cn.json +44 -0
- data/app/locales/zh-tw.json +44 -0
- data/app/views/layouts/super_settings/settings.html.erb +4 -4
- data/config/routes.rb +2 -0
- data/lib/super_settings/application/api.js +37 -12
- data/lib/super_settings/application/helper.rb +78 -11
- data/lib/super_settings/application/index.html.erb +44 -44
- data/lib/super_settings/application/layout.html.erb +113 -6
- data/lib/super_settings/application/layout_styles.css +311 -21
- data/lib/super_settings/application/layout_vars.css.erb +15 -7
- data/lib/super_settings/application/scripts.js +72 -13
- data/lib/super_settings/application/style_vars.css.erb +108 -53
- data/lib/super_settings/application/styles.css +179 -84
- data/lib/super_settings/application.rb +21 -3
- data/lib/super_settings/configuration.rb +27 -5
- data/lib/super_settings/controller_actions.rb +39 -2
- data/lib/super_settings/http_client.rb +2 -1
- data/lib/super_settings/local_cache.rb +12 -16
- data/lib/super_settings/mini_i18n.rb +110 -0
- data/lib/super_settings/rack_application.rb +94 -7
- data/lib/super_settings/rest_api.rb +7 -3
- data/lib/super_settings/setting.rb +1 -1
- data/lib/super_settings/storage/active_record_storage/models.rb +7 -9
- data/lib/super_settings/storage/http_storage.rb +1 -2
- data/lib/super_settings/storage/json_storage.rb +1 -1
- data/lib/super_settings/storage/mongodb_storage.rb +2 -1
- data/lib/super_settings/storage/s3_storage.rb +1 -1
- data/lib/super_settings/storage.rb +1 -1
- data/lib/super_settings/version.rb +1 -1
- data/lib/super_settings.rb +16 -18
- data/super_settings.gemspec +2 -1
- metadata +35 -3
|
@@ -1,42 +1,94 @@
|
|
|
1
|
-
|
|
1
|
+
*, *::before, *::after {
|
|
2
2
|
box-sizing: border-box;
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
3
5
|
}
|
|
4
6
|
|
|
7
|
+
html { font-size: 16px; }
|
|
8
|
+
|
|
5
9
|
body {
|
|
6
|
-
font-family: sans-serif;
|
|
7
|
-
|
|
8
|
-
line-height: 1.5;
|
|
9
|
-
text-align: left;
|
|
10
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
11
|
+
background: var(--background-color);
|
|
10
12
|
color: var(--text-color);
|
|
11
|
-
|
|
13
|
+
line-height: 1.6;
|
|
14
|
+
-webkit-font-smoothing: antialiased;
|
|
15
|
+
-moz-osx-font-smoothing: grayscale;
|
|
12
16
|
margin: 0;
|
|
13
17
|
padding: 0;
|
|
18
|
+
min-height: 100vh;
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
header {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
padding: 1rem;
|
|
21
|
+
.super-settings-page-header {
|
|
22
|
+
border-bottom: 1px solid var(--border-color, #e2e5ea);
|
|
23
|
+
background: var(--header-background-color, #edeef1);
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
header
|
|
23
|
-
|
|
24
|
-
margin: 0;
|
|
26
|
+
.super-settings-page-header-inner {
|
|
27
|
+
max-width: 1280px;
|
|
28
|
+
margin: 0 auto;
|
|
29
|
+
padding: 20px 24px;
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: space-between;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
|
-
header
|
|
28
|
-
|
|
35
|
+
.super-settings-page-header-brand {
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: 12px;
|
|
29
39
|
text-decoration: none;
|
|
40
|
+
color: inherit;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
a.super-settings-page-header-brand:visited {
|
|
44
|
+
color: inherit;
|
|
30
45
|
}
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
|
|
47
|
+
.super-settings-page-header-mark {
|
|
48
|
+
width: 32px;
|
|
49
|
+
height: 32px;
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
color: #0d9488;
|
|
54
|
+
flex-shrink: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.super-settings-page-header-mark svg {
|
|
58
|
+
width: 24px;
|
|
59
|
+
height: 24px;
|
|
33
60
|
}
|
|
34
61
|
|
|
35
|
-
header
|
|
36
|
-
max-height:
|
|
62
|
+
.super-settings-page-header-mark img {
|
|
63
|
+
max-height: 32px;
|
|
64
|
+
max-width: 32px;
|
|
37
65
|
vertical-align: middle;
|
|
38
|
-
|
|
39
|
-
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.super-settings-page-header-title {
|
|
69
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
70
|
+
font-size: 1.125rem;
|
|
71
|
+
font-weight: 700;
|
|
72
|
+
color: var(--text-color);
|
|
73
|
+
letter-spacing: -0.025em;
|
|
74
|
+
line-height: 1.2;
|
|
75
|
+
margin: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.super-settings-page-header-subtitle {
|
|
79
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
80
|
+
font-size: 0.8125rem;
|
|
81
|
+
font-weight: 400;
|
|
82
|
+
color: #9ca3af;
|
|
83
|
+
line-height: 1.3;
|
|
84
|
+
margin: 0;
|
|
85
|
+
letter-spacing: 0.01em;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.super-settings-container {
|
|
89
|
+
max-width: 1280px;
|
|
90
|
+
margin: 0 auto;
|
|
91
|
+
padding: 0 24px;
|
|
40
92
|
}
|
|
41
93
|
|
|
42
94
|
a {
|
|
@@ -47,3 +99,241 @@ a {
|
|
|
47
99
|
a:visited {
|
|
48
100
|
color: var(--link-color);
|
|
49
101
|
}
|
|
102
|
+
|
|
103
|
+
/* ══════════════════════════════════════════
|
|
104
|
+
FOOTER
|
|
105
|
+
══════════════════════════════════════════ */
|
|
106
|
+
|
|
107
|
+
.super-settings-page-footer {
|
|
108
|
+
max-width: 1280px;
|
|
109
|
+
margin: 0 auto;
|
|
110
|
+
padding: 0 24px 24px 24px;
|
|
111
|
+
display: flex;
|
|
112
|
+
justify-content: flex-end;
|
|
113
|
+
}
|
|
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
|
+
|
|
152
|
+
/* ══════════════════════════════════════════
|
|
153
|
+
LANGUAGE MENU (in footer)
|
|
154
|
+
══════════════════════════════════════════ */
|
|
155
|
+
|
|
156
|
+
.super-settings-language-menu {
|
|
157
|
+
position: relative;
|
|
158
|
+
display: block;
|
|
159
|
+
flex-shrink: 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.super-settings-language-menu > summary {
|
|
163
|
+
list-style: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.super-settings-language-menu > summary::-webkit-details-marker {
|
|
167
|
+
display: none;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.super-settings-language-trigger {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 8px;
|
|
174
|
+
padding: 6px 12px;
|
|
175
|
+
border-radius: 6px;
|
|
176
|
+
border: 1px solid var(--border-color, #ccc);
|
|
177
|
+
background: var(--background-color, #fff);
|
|
178
|
+
color: var(--text-color);
|
|
179
|
+
cursor: pointer;
|
|
180
|
+
transition: border-color 0.15s ease, color 0.15s ease;
|
|
181
|
+
max-width: 180px;
|
|
182
|
+
white-space: nowrap;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.super-settings-language-trigger:hover {
|
|
186
|
+
border-color: var(--link-color);
|
|
187
|
+
color: var(--link-color);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.super-settings-language-trigger:focus-visible {
|
|
191
|
+
outline: 2px solid var(--link-color);
|
|
192
|
+
outline-offset: 2px;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.super-settings-language-trigger-icon {
|
|
196
|
+
width: 16px;
|
|
197
|
+
height: 16px;
|
|
198
|
+
display: inline-flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
justify-content: center;
|
|
201
|
+
flex-shrink: 0;
|
|
202
|
+
opacity: 0.7;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.super-settings-language-trigger-icon svg {
|
|
206
|
+
width: 13px;
|
|
207
|
+
height: 13px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.super-settings-language-trigger-current {
|
|
211
|
+
flex: 1;
|
|
212
|
+
min-width: 0;
|
|
213
|
+
font-size: 0.75rem;
|
|
214
|
+
font-weight: 500;
|
|
215
|
+
overflow: hidden;
|
|
216
|
+
text-overflow: ellipsis;
|
|
217
|
+
white-space: nowrap;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.super-settings-language-trigger-caret {
|
|
221
|
+
width: 12px;
|
|
222
|
+
height: 12px;
|
|
223
|
+
display: inline-flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
justify-content: center;
|
|
226
|
+
color: inherit;
|
|
227
|
+
opacity: 0.5;
|
|
228
|
+
transition: transform 0.15s ease, opacity 0.15s ease;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.super-settings-language-trigger-caret svg {
|
|
232
|
+
width: 100%;
|
|
233
|
+
height: 100%;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.super-settings-language-menu[open] .super-settings-language-trigger {
|
|
237
|
+
border-color: var(--link-color);
|
|
238
|
+
color: var(--link-color);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.super-settings-language-menu[open] .super-settings-language-trigger-caret {
|
|
242
|
+
opacity: 0.8;
|
|
243
|
+
transform: rotate(180deg);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.super-settings-language-popup {
|
|
247
|
+
position: absolute;
|
|
248
|
+
right: 0;
|
|
249
|
+
bottom: calc(100% + 6px);
|
|
250
|
+
min-width: 160px;
|
|
251
|
+
max-height: 260px;
|
|
252
|
+
margin: 0;
|
|
253
|
+
padding: 4px;
|
|
254
|
+
background: var(--background-color, #fff);
|
|
255
|
+
border: 1px solid var(--border-color, #ccc);
|
|
256
|
+
border-radius: 8px;
|
|
257
|
+
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
|
|
258
|
+
opacity: 0;
|
|
259
|
+
transform: translateY(4px);
|
|
260
|
+
pointer-events: none;
|
|
261
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
262
|
+
overflow-y: auto;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.super-settings-language-popup li {
|
|
266
|
+
list-style: none;
|
|
267
|
+
margin: 0;
|
|
268
|
+
padding: 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.super-settings-language-menu[open] .super-settings-language-popup {
|
|
272
|
+
opacity: 1;
|
|
273
|
+
transform: translateY(0);
|
|
274
|
+
pointer-events: auto;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.super-settings-language-option {
|
|
278
|
+
width: 100%;
|
|
279
|
+
display: flex;
|
|
280
|
+
align-items: center;
|
|
281
|
+
gap: 8px;
|
|
282
|
+
padding: 6px 10px;
|
|
283
|
+
border: none;
|
|
284
|
+
border-radius: 4px;
|
|
285
|
+
background: transparent;
|
|
286
|
+
color: var(--text-color);
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
text-align: start;
|
|
289
|
+
transition: background 0.1s ease;
|
|
290
|
+
font-family: inherit;
|
|
291
|
+
font-weight: 500;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.super-settings-language-option-name {
|
|
295
|
+
flex: 1;
|
|
296
|
+
min-width: 0;
|
|
297
|
+
font-size: 0.75rem;
|
|
298
|
+
overflow: hidden;
|
|
299
|
+
white-space: nowrap;
|
|
300
|
+
text-overflow: ellipsis;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.super-settings-language-option:hover,
|
|
304
|
+
.super-settings-language-option:focus-visible {
|
|
305
|
+
background: var(--border-color, #eee);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.super-settings-language-option-check {
|
|
309
|
+
width: 12px;
|
|
310
|
+
height: 12px;
|
|
311
|
+
color: var(--link-color);
|
|
312
|
+
opacity: 0;
|
|
313
|
+
transform: scale(0.5);
|
|
314
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
315
|
+
flex-shrink: 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.super-settings-language-option-check svg {
|
|
319
|
+
width: 100%;
|
|
320
|
+
height: 100%;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.super-settings-language-option.is-active {
|
|
324
|
+
background: color-mix(in srgb, var(--link-color) 10%, transparent);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.super-settings-language-option.is-active .super-settings-language-option-check {
|
|
328
|
+
opacity: 1;
|
|
329
|
+
transform: scale(1);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
@media (max-width: 640px) {
|
|
333
|
+
.super-settings-page-header-inner {
|
|
334
|
+
padding: 16px 24px;
|
|
335
|
+
}
|
|
336
|
+
.super-settings-page-footer {
|
|
337
|
+
padding: 0 24px 16px 24px;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
<% unless color_scheme
|
|
1
|
+
<% unless color_scheme == :dark %>
|
|
2
2
|
:root {
|
|
3
|
-
--text-color: #
|
|
4
|
-
--background-color: #
|
|
5
|
-
--
|
|
3
|
+
--text-color: #111827;
|
|
4
|
+
--background-color: #f4f5f7;
|
|
5
|
+
--header-background-color: #edeef1;
|
|
6
|
+
--link-color: #0d9488;
|
|
7
|
+
--border-color: #e2e5ea;
|
|
6
8
|
}
|
|
7
9
|
<% end %>
|
|
8
10
|
|
|
@@ -11,9 +13,15 @@
|
|
|
11
13
|
<% end %>
|
|
12
14
|
<% if color_scheme == :system || color_scheme == :dark %>
|
|
13
15
|
:root {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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;
|
|
21
|
+
--background-color: #1a1d23;
|
|
22
|
+
--header-background-color: #21252b;
|
|
23
|
+
--link-color: #2dd4bf;
|
|
24
|
+
--border-color: #363b44;
|
|
17
25
|
}
|
|
18
26
|
<% end %>
|
|
19
27
|
<% if color_scheme == :system %>
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
(function() {
|
|
2
|
+
// ── i18n helper ──
|
|
3
|
+
const _i18n = window.__superSettingsI18n || {};
|
|
4
|
+
const t = (key) => _i18n[key] || key;
|
|
5
|
+
|
|
2
6
|
// Return the card element for a setting.
|
|
3
7
|
function findSettingCard(id) {
|
|
4
8
|
if (id) {
|
|
@@ -29,6 +33,8 @@
|
|
|
29
33
|
countSpan.innerHTML = count;
|
|
30
34
|
discardButton.disabled = false;
|
|
31
35
|
}
|
|
36
|
+
// Force repaint to prevent Safari box-shadow artifact when button width changes
|
|
37
|
+
void saveButton.offsetWidth;
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
|
|
@@ -255,6 +261,7 @@
|
|
|
255
261
|
}
|
|
256
262
|
bindSettingControlEvents(card);
|
|
257
263
|
filterSettings(document.querySelector("#super-settings-filter").value);
|
|
264
|
+
card.classList.add("super-settings-card-reveal");
|
|
258
265
|
card.scrollIntoView({block: "nearest"});
|
|
259
266
|
enableSaveButton();
|
|
260
267
|
return card;
|
|
@@ -277,7 +284,11 @@
|
|
|
277
284
|
|
|
278
285
|
// Update the settings count display.
|
|
279
286
|
function updateSettingsCount(count) {
|
|
280
|
-
document.querySelector(".js-settings-count").textContent = `${count} ${count === 1 ? "
|
|
287
|
+
document.querySelector(".js-settings-count").textContent = `${count} ${count === 1 ? t("count.setting") : t("count.settings")}`;
|
|
288
|
+
const sortControls = document.querySelector(".super-settings-sort-controls");
|
|
289
|
+
if (sortControls) {
|
|
290
|
+
sortControls.style.display = (count > 0) ? "" : "none";
|
|
291
|
+
}
|
|
281
292
|
}
|
|
282
293
|
|
|
283
294
|
// Apply the given filter to only show settings that have a key, value, or description
|
|
@@ -358,7 +369,7 @@
|
|
|
358
369
|
flash.classList.add("super-settings-text-success");
|
|
359
370
|
flash.classList.remove("super-settings-text-danger");
|
|
360
371
|
} else {
|
|
361
|
-
flash.classList.add("
|
|
372
|
+
flash.classList.add("super-settings-text-danger");
|
|
362
373
|
flash.classList.remove("super-settings-text-success");
|
|
363
374
|
}
|
|
364
375
|
flash.innerText = message;
|
|
@@ -366,6 +377,13 @@
|
|
|
366
377
|
dismissFlash();
|
|
367
378
|
}
|
|
368
379
|
|
|
380
|
+
// Show an API error in the flash message area instead of using window.alert.
|
|
381
|
+
function showAPIError(error) {
|
|
382
|
+
console.error("Error:", error);
|
|
383
|
+
const message = t("error.generic");
|
|
384
|
+
showFlash(message, false);
|
|
385
|
+
}
|
|
386
|
+
|
|
369
387
|
// Automatically hide the flash message displaying the results of the last save operation.
|
|
370
388
|
function dismissFlash() {
|
|
371
389
|
if (document.querySelector(".js-flash")) {
|
|
@@ -392,12 +410,12 @@
|
|
|
392
410
|
function renderHistoryTable(parent, payload) {
|
|
393
411
|
parent.innerHTML = document.querySelector("#setting-history-table").innerHTML.trim();
|
|
394
412
|
parent.querySelector(".super-settings-history-key").innerText = payload.key;
|
|
395
|
-
const historyItems = parent.querySelector("
|
|
413
|
+
const historyItems = parent.querySelector(".super-settings-history-items");
|
|
396
414
|
let itemsHTML = "";
|
|
397
415
|
payload.histories.forEach(function(history) {
|
|
398
416
|
const date = new Date(Date.parse(history.created_at));
|
|
399
417
|
const dateString = dateFormatter().format(date);
|
|
400
|
-
const value = (history.deleted ? '<em class="super-settings-text-danger">deleted</em>' : escapeHTML(history.value));
|
|
418
|
+
const value = (history.deleted ? '<em class="super-settings-text-danger">' + escapeHTML(t("history.deleted")) + '</em>' : escapeHTML(history.value));
|
|
401
419
|
itemsHTML += `<div class="super-settings-history-item">
|
|
402
420
|
<div class="super-settings-history-time">${escapeHTML(dateString)}</div>
|
|
403
421
|
<div class="super-settings-history-user">${escapeHTML(history.changed_by)}</div>
|
|
@@ -409,10 +427,10 @@
|
|
|
409
427
|
if (payload.previous_page_params || payload.next_page_params) {
|
|
410
428
|
let paginationHTML = `<div class="super-settings-align-center">`;
|
|
411
429
|
if (payload.previous_page_params) {
|
|
412
|
-
paginationHTML += `<div style="float:left;"><a href="#" class="js-show-history" title="
|
|
430
|
+
paginationHTML += `<div style="float:left;"><a href="#" class="js-show-history" title="${escapeHTML(t("history.newer"))}" data-offset="${payload.previous_page_params.offset}" data-limit="${payload.previous_page_params.limit}" data-key="${payload.previous_page_params.key}")>← ${escapeHTML(t("history.newer"))}</a></div>`;
|
|
413
431
|
}
|
|
414
432
|
if (payload.next_page_params) {
|
|
415
|
-
paginationHTML += `<div style="float:right;"><a href="#" class="js-show-history" title="
|
|
433
|
+
paginationHTML += `<div style="float:right;"><a href="#" class="js-show-history" title="${escapeHTML(t("history.older"))}" data-offset="${payload.next_page_params.offset}" data-limit="${payload.next_page_params.limit}" data-key="${payload.next_page_params.key}")>${escapeHTML(t("history.older"))} →</a></div>`;
|
|
416
434
|
}
|
|
417
435
|
paginationHTML += '<div style="clear:both;"></div>';
|
|
418
436
|
parent.querySelector(".super-settings-history-container").insertAdjacentHTML("afterend", paginationHTML);
|
|
@@ -538,7 +556,7 @@
|
|
|
538
556
|
SuperSettingsAPI.fetchHistory(params, function(settingHistory){
|
|
539
557
|
renderHistoryTable(content, settingHistory);
|
|
540
558
|
showModal();
|
|
541
|
-
});
|
|
559
|
+
}, showAPIError);
|
|
542
560
|
}
|
|
543
561
|
|
|
544
562
|
// Listener for closing the modal window overlay.
|
|
@@ -611,6 +629,7 @@
|
|
|
611
629
|
if (setting) {
|
|
612
630
|
const newCard = settingCard(setting);
|
|
613
631
|
bindSettingControlEvents(newCard);
|
|
632
|
+
newCard.classList.add("super-settings-card-reveal");
|
|
614
633
|
card.replaceWith(newCard);
|
|
615
634
|
} else {
|
|
616
635
|
card.remove();
|
|
@@ -676,15 +695,15 @@
|
|
|
676
695
|
SuperSettingsAPI.updateSettings({settings: settingsData}, function(results) {
|
|
677
696
|
if (results.success) {
|
|
678
697
|
fetchActiveSettings();
|
|
679
|
-
showFlash("
|
|
698
|
+
showFlash(t("flash.saved"), true)
|
|
680
699
|
} else {
|
|
681
700
|
event.target.disabled = false;
|
|
682
|
-
showFlash("
|
|
701
|
+
showFlash(t("flash.save_failed"), false)
|
|
683
702
|
if (results.errors) {
|
|
684
703
|
showValidationErrors(results.errors)
|
|
685
704
|
}
|
|
686
705
|
}
|
|
687
|
-
});
|
|
706
|
+
}, showAPIError);
|
|
688
707
|
}
|
|
689
708
|
|
|
690
709
|
// Listener for the filter input field.
|
|
@@ -861,7 +880,7 @@
|
|
|
861
880
|
|
|
862
881
|
function promptUnsavedChanges(event) {
|
|
863
882
|
if (changesCount() > 0) {
|
|
864
|
-
return "
|
|
883
|
+
return t("prompt.unsaved");
|
|
865
884
|
} else {
|
|
866
885
|
return undefined;
|
|
867
886
|
}
|
|
@@ -881,7 +900,7 @@
|
|
|
881
900
|
const settings = settings_hash["settings"];
|
|
882
901
|
activeSettings = settings;
|
|
883
902
|
renderSettingsContainer(settings);
|
|
884
|
-
if (hashParams && hashParams.edit) {
|
|
903
|
+
if (hashParams && hashParams.edit && !document.querySelector(".super-settings[data-read-only]")) {
|
|
885
904
|
const setting = findSettingByKey(hashParams.edit);
|
|
886
905
|
if (setting) {
|
|
887
906
|
editSetting(setting);
|
|
@@ -890,12 +909,17 @@
|
|
|
890
909
|
}
|
|
891
910
|
}
|
|
892
911
|
enableSaveButton();
|
|
893
|
-
});
|
|
912
|
+
}, showAPIError);
|
|
894
913
|
}
|
|
895
914
|
|
|
896
915
|
let activeSettings = [];
|
|
897
916
|
|
|
898
917
|
docReady(function() {
|
|
918
|
+
const appElement = document.querySelector(".super-settings[data-api-base-url]");
|
|
919
|
+
if (appElement) {
|
|
920
|
+
SuperSettingsAPI.baseUrl = appElement.dataset.apiBaseUrl;
|
|
921
|
+
}
|
|
922
|
+
|
|
899
923
|
storeAccessToken();
|
|
900
924
|
|
|
901
925
|
addListener(document.querySelector("#super-settings-filter"), "input", filterListener);
|
|
@@ -915,5 +939,40 @@
|
|
|
915
939
|
fetchActiveSettings(hashParams);
|
|
916
940
|
|
|
917
941
|
window.onbeforeunload = promptUnsavedChanges;
|
|
942
|
+
|
|
943
|
+
// ── Language Menu ──
|
|
944
|
+
const languageMenu = document.getElementById("super-settings-language-menu");
|
|
945
|
+
const languageOptions = document.querySelectorAll(".super-settings-language-option");
|
|
946
|
+
const closeLanguageMenu = () => {
|
|
947
|
+
if (languageMenu) languageMenu.removeAttribute("open");
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
if (languageMenu && languageOptions.length > 0) {
|
|
951
|
+
languageOptions.forEach((option) => {
|
|
952
|
+
option.addEventListener("click", () => {
|
|
953
|
+
const locale = option.dataset.locale;
|
|
954
|
+
if (!locale) return;
|
|
955
|
+
|
|
956
|
+
closeLanguageMenu();
|
|
957
|
+
|
|
958
|
+
// Persist the choice in a cookie (accessible server-side)
|
|
959
|
+
document.cookie = "super_settings_locale=" + encodeURIComponent(locale) + ";path=/;max-age=31536000;SameSite=Lax";
|
|
960
|
+
|
|
961
|
+
// Also store in localStorage for client-side persistence
|
|
962
|
+
try { localStorage.setItem("super_settings_locale", locale); } catch(e) {}
|
|
963
|
+
|
|
964
|
+
// Reload with lang query param so server picks it up immediately
|
|
965
|
+
const url = new URL(window.location.href);
|
|
966
|
+
url.searchParams.set("lang", locale);
|
|
967
|
+
window.location.href = url.toString();
|
|
968
|
+
});
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
document.addEventListener("click", (e) => {
|
|
972
|
+
if (languageMenu.hasAttribute("open") && !e.target.closest("#super-settings-language-menu")) {
|
|
973
|
+
closeLanguageMenu();
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
}
|
|
918
977
|
})
|
|
919
978
|
})();
|