super_settings 2.4.2 → 2.5.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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +27 -0
  3. data/ARCHITECTURE.md +232 -0
  4. data/CHANGELOG.md +31 -1
  5. data/README.md +49 -0
  6. data/VERSION +1 -1
  7. data/app/helpers/super_settings/settings_helper.rb +4 -11
  8. data/app/locales/ar.json +44 -0
  9. data/app/locales/cs.json +44 -0
  10. data/app/locales/da.json +44 -0
  11. data/app/locales/de.json +44 -0
  12. data/app/locales/el.json +44 -0
  13. data/app/locales/en.json +55 -0
  14. data/app/locales/es.json +44 -0
  15. data/app/locales/fa.json +44 -0
  16. data/app/locales/fr.json +44 -0
  17. data/app/locales/gd.json +44 -0
  18. data/app/locales/he.json +44 -0
  19. data/app/locales/hi.json +44 -0
  20. data/app/locales/it.json +44 -0
  21. data/app/locales/ja.json +44 -0
  22. data/app/locales/ko.json +44 -0
  23. data/app/locales/lt.json +44 -0
  24. data/app/locales/nb.json +44 -0
  25. data/app/locales/nl.json +44 -0
  26. data/app/locales/pl.json +44 -0
  27. data/app/locales/pt-br.json +44 -0
  28. data/app/locales/pt.json +44 -0
  29. data/app/locales/ru.json +44 -0
  30. data/app/locales/sv.json +44 -0
  31. data/app/locales/ta.json +44 -0
  32. data/app/locales/tr.json +44 -0
  33. data/app/locales/uk.json +44 -0
  34. data/app/locales/ur.json +44 -0
  35. data/app/locales/vi.json +44 -0
  36. data/app/locales/zh-cn.json +44 -0
  37. data/app/locales/zh-tw.json +44 -0
  38. data/app/views/layouts/super_settings/settings.html.erb +4 -4
  39. data/config/routes.rb +2 -0
  40. data/lib/super_settings/application/api.js +37 -12
  41. data/lib/super_settings/application/helper.rb +70 -11
  42. data/lib/super_settings/application/index.html.erb +44 -44
  43. data/lib/super_settings/application/layout.html.erb +57 -6
  44. data/lib/super_settings/application/layout_styles.css +274 -21
  45. data/lib/super_settings/application/layout_vars.css.erb +11 -7
  46. data/lib/super_settings/application/scripts.js +72 -13
  47. data/lib/super_settings/application/style_vars.css.erb +104 -51
  48. data/lib/super_settings/application/styles.css +179 -84
  49. data/lib/super_settings/application.rb +16 -1
  50. data/lib/super_settings/controller_actions.rb +33 -1
  51. data/lib/super_settings/http_client.rb +2 -1
  52. data/lib/super_settings/local_cache.rb +12 -16
  53. data/lib/super_settings/mini_i18n.rb +110 -0
  54. data/lib/super_settings/rack_application.rb +84 -5
  55. data/lib/super_settings/rest_api.rb +7 -3
  56. data/lib/super_settings/setting.rb +1 -1
  57. data/lib/super_settings/storage/active_record_storage/models.rb +8 -22
  58. data/lib/super_settings/storage/http_storage.rb +1 -2
  59. data/lib/super_settings/storage/json_storage.rb +1 -1
  60. data/lib/super_settings/storage/mongodb_storage.rb +2 -1
  61. data/lib/super_settings/storage/s3_storage.rb +1 -1
  62. data/lib/super_settings/storage.rb +1 -1
  63. data/lib/super_settings/version.rb +1 -1
  64. data/lib/super_settings.rb +16 -18
  65. data/super_settings.gemspec +2 -1
  66. metadata +35 -3
@@ -1,43 +1,71 @@
1
1
  .super-settings {
2
- --primary-color-h: 216;
3
- --primary-color-s: 98%;
4
- --primary-color-l: 52%;
2
+ --font-ui: system-ui, -apple-system, sans-serif;
3
+ --font-mono: "SF Mono", Menlo, Consolas, monospace;
4
+
5
+ --primary-color-h: 174;
6
+ --primary-color-s: 84%;
7
+ --primary-color-l: 29%;
5
8
  --primary-color-hsl: var(--primary-color-h), var(--primary-color-s), var(--primary-color-l);
6
9
  --primary-color: hsl(var(--primary-color-hsl));
7
10
  --primary-contrast-color: #fff;
8
- --primary-hover-color: hsl(var(--primary-color-h), var(--primary-color-s), calc(var(--primary-color-l) - 10%));
11
+ --primary-hover-color: hsl(var(--primary-color-h), var(--primary-color-s), calc(var(--primary-color-l) - 5%));
9
12
  --primary-border-color: hsl(var(--primary-color-h), var(--primary-color-s), calc(var(--primary-color-l) + 10%));
10
13
  }
11
14
 
12
15
  <% unless color_scheme == :dark %>
13
16
  .super-settings {
14
- --edit-bg-color: #f2fdf2;
15
- --deleted-row-color: darkred;
16
- --deleted-row-bg-color: #ffd1d8;
17
- --history-key-color: royalblue;
18
- --table-header-bg-color: #fff;
19
- --table-border-color: #dee2e6;
20
- --alt-row-color: rgba(0, 0, 0, .03);
21
- --form-control-color: #495057;
17
+ /* Canvas */
18
+ --bg-page: #f4f5f7;
19
+ --bg-card: #ffffff;
20
+ --bg-code: #f0f2f5;
21
+
22
+ /* Borders */
23
+ --border-light: #e2e5ea;
24
+ --border-card: #dfe2e8;
25
+
26
+ /* Text */
27
+ --text-primary: #111827;
28
+ --text-secondary: #4b5563;
29
+ --text-tertiary: #9ca3af;
30
+
31
+ /* Accent */
32
+ --accent: #0d9488;
33
+ --accent-light: rgba(13, 148, 136, 0.06);
34
+ --accent-glow: rgba(13, 148, 136, 0.12);
35
+
36
+ /* Shadows */
37
+ --shadow-card: 0 1px 3px rgba(0,0,0,0.04), 0 0 0 1px rgba(0,0,0,0.03);
38
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
39
+ --shadow-lg: 0 20px 48px rgba(0,0,0,0.12);
40
+
41
+ /* Mapped vars for existing components */
42
+ --edit-bg-color: rgba(13, 148, 136, 0.06);
43
+ --deleted-row-color: #dc2626;
44
+ --deleted-row-bg-color: #fef2f2;
45
+ --history-key-color: #0d9488;
46
+ --table-header-bg-color: #f4f5f7;
47
+ --table-border-color: #dfe2e8;
48
+ --alt-row-color: rgba(0, 0, 0, .02);
49
+ --form-control-color: #111827;
22
50
  --form-control-bg-color: #fff;
23
- --form-control-border-color: #ced4da;
24
- --form-control-placeholder-color: #bbb;
51
+ --form-control-border-color: #dfe2e8;
52
+ --form-control-placeholder-color: #9ca3af;
25
53
  --modal-bg-color: #fff;
26
- --modal-transparency: 0.4;
27
- --modal-control-color: #000;
28
- --success-color: green;
29
- --danger-color: firebrick;
30
- --muted-color: #999;
31
- --unselected-color: #666;
32
- --btn-hover-color: #e9e9e9;
54
+ --modal-transparency: 0.5;
55
+ --modal-control-color: #111827;
56
+ --success-color: #059669;
57
+ --danger-color: #dc2626;
58
+ --muted-color: #9ca3af;
59
+ --unselected-color: #4b5563;
60
+ --btn-hover-color: #f0f2f5;
33
61
  --card-bg-color: #fff;
34
62
 
35
63
  /* Icon Colors */
36
- --icon-info-color: #0d7ff0;
37
- --icon-edit-color: #0c8024;
38
- --icon-delete-color: #dc3545;
39
- --icon-cancel-color: #dc3545;
40
- --icon-disabled-color: #c0c0c0;
64
+ --icon-info-color: #0d9488;
65
+ --icon-edit-color: #059669;
66
+ --icon-delete-color: #dc2626;
67
+ --icon-cancel-color: #dc2626;
68
+ --icon-disabled-color: #d1d5db;
41
69
  }
42
70
  <% end %>
43
71
 
@@ -46,33 +74,58 @@
46
74
  <% end %>
47
75
  <% if color_scheme == :system || color_scheme == :dark %>
48
76
  .super-settings {
49
- --edit-bg-color: #437330;
50
- --deleted-row-color: #e0b1b8;
51
- --deleted-row-bg-color: #7a3636;
52
- --history-key-color: #a7d6f4;
53
- --table-header-bg-color: #333;
54
- --table-border-color: #555;
55
- --alt-row-color: rgba(0, 0, 0, .30);
56
- --form-control-color: #eee;
57
- --form-control-bg-color: #666;
58
- --form-control-border-color: #555;
59
- --btn-hover-color: #c0c0c0;
60
- --form-control-placeholder-color: #aaa;
61
- --modal-bg-color: #333;
62
- --modal-transparency: 0.75;
63
- --modal-control-color: #fff;
64
- --success-color: #00ff00;
65
- --danger-color: #ff0000;
66
- --muted-color: #ccc;
67
- --unselected-color: #ccc;
68
- --card-bg-color: #484848;
77
+ /* Canvas */
78
+ --bg-page: #1a1d23;
79
+ --bg-card: #23272e;
80
+ --bg-code: #2a2e36;
81
+
82
+ /* Borders */
83
+ --border-light: #363b44;
84
+ --border-card: #363b44;
85
+
86
+ /* Text */
87
+ --text-primary: #e5e7eb;
88
+ --text-secondary: #9ca3af;
89
+ --text-tertiary: #6b7280;
90
+
91
+ /* Accent */
92
+ --accent: #2dd4bf;
93
+ --accent-light: rgba(45, 212, 191, 0.08);
94
+ --accent-glow: rgba(45, 212, 191, 0.15);
95
+
96
+ /* Shadows */
97
+ --shadow-card: 0 1px 3px rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.1);
98
+ --shadow-sm: 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2);
99
+ --shadow-lg: 0 20px 48px rgba(0,0,0,0.4);
100
+
101
+ /* Mapped vars */
102
+ --edit-bg-color: rgba(45, 212, 191, 0.08);
103
+ --deleted-row-color: #fca5a5;
104
+ --deleted-row-bg-color: rgba(220, 38, 38, 0.15);
105
+ --history-key-color: #2dd4bf;
106
+ --table-header-bg-color: #1a1d23;
107
+ --table-border-color: #363b44;
108
+ --alt-row-color: rgba(255, 255, 255, .03);
109
+ --form-control-color: #e5e7eb;
110
+ --form-control-bg-color: #2a2e36;
111
+ --form-control-border-color: #363b44;
112
+ --form-control-placeholder-color: #6b7280;
113
+ --modal-bg-color: #23272e;
114
+ --modal-transparency: 0.7;
115
+ --modal-control-color: #e5e7eb;
116
+ --success-color: #34d399;
117
+ --danger-color: #f87171;
118
+ --muted-color: #6b7280;
119
+ --unselected-color: #9ca3af;
120
+ --btn-hover-color: #2a2e36;
121
+ --card-bg-color: #23272e;
69
122
 
70
123
  /* Icon Colors */
71
- --icon-info-color: #71b0f0;
72
- --icon-edit-color: #7dde90;
73
- --icon-delete-color: #eb8791;
74
- --icon-cancel-color: #eb8791;
75
- --icon-disabled-color: #aaa;
124
+ --icon-info-color: #2dd4bf;
125
+ --icon-edit-color: #34d399;
126
+ --icon-delete-color: #f87171;
127
+ --icon-cancel-color: #f87171;
128
+ --icon-disabled-color: #4b5563;
76
129
  }
77
130
  <% end %>
78
131
  <% if color_scheme == :system %>
@@ -1,6 +1,11 @@
1
+ .super-settings {
2
+ padding: 0 12px;
3
+ background-color: var(--bg-page, #f4f5f7);
4
+ }
5
+
1
6
  .super-settings-container {
2
- padding-left: 15px;
3
- padding-right: 15px;
7
+ padding-left: 24px;
8
+ padding-right: 24px;
4
9
  margin-left: auto;
5
10
  margin-right: auto;
6
11
  }
@@ -9,25 +14,23 @@
9
14
  .super-settings-cards-container {
10
15
  display: flex;
11
16
  flex-direction: column;
12
- gap: 0.75rem;
17
+ gap: 10px;
13
18
  padding: 1rem 0;
14
19
  }
15
20
 
16
21
  .super-settings-card {
17
- border: 2px solid var(--table-border-color);
18
- border-radius: 0.5rem;
19
- background-color: var(--card-bg-color);
20
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
21
- transition: box-shadow 0.2s ease-in-out;
22
+ border: 1px solid var(--border-card, var(--table-border-color));
23
+ border-radius: 10px;
24
+ background-color: var(--bg-card, var(--card-bg-color));
25
+ box-shadow: var(--shadow-card, 0 1px 3px rgba(0, 0, 0, 0.04));
26
+ transition: box-shadow 0.15s ease, border-color 0.15s ease;
22
27
  width: 100%;
28
+ overflow: hidden;
29
+ scroll-margin-top: 80px;
23
30
  }
24
31
 
25
32
  .super-settings-card:hover {
26
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
27
- }
28
-
29
- .super-settings-cards-container .super-settings-card:nth-child(even) {
30
- background-color: var(--alt-row-color);
33
+ box-shadow: var(--shadow-sm, 0 2px 8px rgba(0, 0, 0, 0.1));
31
34
  }
32
35
 
33
36
  .super-settings-card-edit {
@@ -57,7 +60,7 @@
57
60
  grid-template-columns: 2fr 2fr 1fr 3fr 1fr 1fr;
58
61
  gap: 1rem;
59
62
  align-items: start;
60
- padding: 1rem;
63
+ padding: 14px 18px;
61
64
  }
62
65
 
63
66
  .super-settings-card-key {
@@ -91,7 +94,7 @@
91
94
  /* Mobile layout - stacked */
92
95
  @media (max-width: 767px) {
93
96
  .super-settings-card-content {
94
- padding: 1rem;
97
+ padding: 14px 18px;
95
98
  }
96
99
 
97
100
  .super-settings-card-key {
@@ -133,12 +136,12 @@
133
136
 
134
137
  .super-settings-card-label {
135
138
  display: block;
136
- font-size: 0.75rem;
139
+ font-size: 0.6875rem;
137
140
  font-weight: 600;
138
- color: var(--muted-color);
141
+ color: var(--text-tertiary, var(--muted-color));
139
142
  margin-bottom: 0.25rem;
140
143
  text-transform: uppercase;
141
- letter-spacing: 0.025em;
144
+ letter-spacing: 0.05em;
142
145
  }
143
146
 
144
147
  /* Sort Controls */
@@ -148,7 +151,7 @@
148
151
  grid-template-columns: 2fr 2fr 1fr 3fr 1fr 1fr;
149
152
  gap: 1rem;
150
153
  align-items: center;
151
- padding: 0.125rem 1rem 0.125rem 1rem;
154
+ padding: 0.125rem 18px 0.125rem 18px;
152
155
  background-color: transparent;
153
156
  border: none;
154
157
  margin-bottom: 0.25rem;
@@ -161,15 +164,18 @@
161
164
  .super-settings-sort-controls .super-settings-sort-control {
162
165
  padding: 0.125rem 0;
163
166
  margin: 0;
164
- margin-top: 1rem; /* Align with card content that has labels */
167
+ margin-top: 1rem;
165
168
  text-align: left;
166
169
  font-weight: 600;
167
- color: var(--form-control-color);
170
+ font-size: 0.75rem;
171
+ color: var(--text-tertiary, var(--form-control-color));
172
+ text-transform: uppercase;
173
+ letter-spacing: 0.05em;
168
174
  }
169
175
 
170
176
  .super-settings-sort-controls > span {
171
177
  font-weight: 600;
172
- color: var(--form-control-color);
178
+ color: var(--text-tertiary, var(--form-control-color));
173
179
  }
174
180
  }
175
181
 
@@ -178,16 +184,25 @@
178
184
  .super-settings-sort-controls {
179
185
  display: flex;
180
186
  align-items: center;
181
- gap: 1rem;
187
+ flex-wrap: wrap;
188
+ gap: 0.5rem;
182
189
  margin-bottom: 0.5rem;
183
- padding: 0.25rem 1rem;
190
+ padding: 0.25rem 0;
184
191
  background-color: transparent;
185
192
  border: none;
186
193
  }
187
194
 
195
+ .super-settings-sort-controls > span:empty {
196
+ display: none;
197
+ }
198
+
188
199
  .super-settings-sort-label {
189
200
  font-weight: 600;
190
- color: var(--form-control-color);
201
+ font-size: 0.75rem;
202
+ color: var(--text-tertiary, var(--form-control-color));
203
+ text-transform: uppercase;
204
+ letter-spacing: 0.05em;
205
+ margin-right: 0.25rem;
191
206
  }
192
207
 
193
208
  .super-settings-sort-control {
@@ -195,15 +210,16 @@
195
210
  align-items: center;
196
211
  gap: 0.25rem;
197
212
  padding: 0.25rem 0.5rem;
198
- border: 1px solid transparent;
199
- border-radius: 0.25rem;
200
- transition: all 0.2s ease-in-out;
213
+ border: none;
214
+ border-radius: 6px;
215
+ transition: all 0.15s ease;
216
+ font-size: 0.8125rem;
217
+ font-weight: 600;
218
+ color: var(--text-tertiary, var(--form-control-color));
201
219
  }
202
220
 
203
221
  .super-settings-sort-control[data-selected="true"] {
204
- background-color: var(--primary-color);
205
- color: var(--primary-contrast-color);
206
- border-color: var(--primary-border-color);
222
+ color: var(--primary-color);
207
223
  }
208
224
  }
209
225
 
@@ -228,7 +244,7 @@
228
244
  }
229
245
 
230
246
  .super-settings-sort-control {
231
- color: var(--unselected-color);
247
+ color: var(--text-tertiary, var(--unselected-color));
232
248
  }
233
249
 
234
250
  .super-settings-sort-control svg {
@@ -244,6 +260,7 @@
244
260
  .super-settings-history-key {
245
261
  font-weight: normal;
246
262
  color: var(--history-key-color);
263
+ font-family: var(--font-mono, "SF Mono", Menlo, Consolas, monospace);
247
264
  }
248
265
 
249
266
  /* History Display Layout */
@@ -258,8 +275,11 @@
258
275
  gap: 1rem;
259
276
  padding: 0.75rem;
260
277
  font-weight: 600;
261
- border-bottom: 2px solid var(--table-border-color);
262
- background-color: var(--table-header-bg-color);
278
+ font-size: 0.75rem;
279
+ text-transform: uppercase;
280
+ letter-spacing: 0.05em;
281
+ color: var(--text-tertiary, inherit);
282
+ border-bottom: 1px solid var(--border-card, var(--table-border-color));
263
283
  }
264
284
 
265
285
  .super-settings-history-items {
@@ -272,8 +292,9 @@
272
292
  grid-template-columns: 2fr 2fr 3fr;
273
293
  gap: 1rem;
274
294
  padding: 0.75rem;
275
- border-bottom: 1px solid var(--table-border-color);
295
+ border-bottom: 1px solid var(--border-light, var(--table-border-color));
276
296
  align-items: start;
297
+ font-size: 0.875rem;
277
298
  }
278
299
 
279
300
  .super-settings-history-item:nth-of-type(even) {
@@ -290,6 +311,8 @@
290
311
 
291
312
  .super-settings-history-value {
292
313
  word-break: break-word;
314
+ font-family: var(--font-mono, "SF Mono", Menlo, Consolas, monospace);
315
+ font-size: 0.8125rem;
293
316
  }
294
317
 
295
318
  /* Mobile responsive layout for history */
@@ -302,13 +325,13 @@
302
325
  display: block;
303
326
  padding: 1rem;
304
327
  margin-bottom: 0.5rem;
305
- border: 1px solid var(--table-border-color);
306
- border-radius: 0.5rem;
307
- background-color: var(--form-control-bg-color);
328
+ border: 1px solid var(--border-card, var(--table-border-color));
329
+ border-radius: 10px;
330
+ background-color: var(--bg-card, var(--form-control-bg-color));
308
331
  }
309
332
 
310
333
  .super-settings-history-item:nth-of-type(odd) {
311
- background-color: var(--form-control-bg-color);
334
+ background-color: var(--bg-card, var(--form-control-bg-color));
312
335
  }
313
336
 
314
337
  .super-settings-history-time,
@@ -326,43 +349,56 @@
326
349
  .super-settings-modal {
327
350
  z-index: 1000000000000;
328
351
  display: none;
329
- padding-top: 5rem;
330
352
  position: fixed;
331
- left: 0;
332
- top: 0;
333
- width: 100%;
334
- height: 100%;
353
+ inset: 0;
335
354
  overflow: auto;
336
- background-color: rgba(0, 0, 0, var(--modal-transparency));
355
+ background-color: rgba(30, 37, 48, var(--modal-transparency, 0.5));
337
356
  }
338
357
 
339
358
  .super-settings-modal-dialog {
340
- margin: auto;
341
- background-color: var(--modal-bg-color);
359
+ margin: 5rem auto;
360
+ background-color: var(--bg-card, var(--modal-bg-color));
342
361
  position: relative;
343
362
  outline: 0;
344
- padding: 2em;
345
- box-shadow: 3px 3px 7px 3px rgba(0, 0, 0, 0.6);
346
- border-radius: 4px;
363
+ padding: 24px;
364
+ box-shadow: var(--shadow-lg, 0 20px 48px rgba(0, 0, 0, 0.12));
365
+ border-radius: 10px;
366
+ border: 1px solid var(--border-card, transparent);
347
367
  width: 80%;
348
- height: 80%;
368
+ max-height: 80vh;
369
+ display: flex;
370
+ flex-direction: column;
349
371
  }
350
372
 
351
373
  .super-settings-modal-content {
352
- height: 100%;
374
+ flex: 1;
353
375
  overflow: auto;
354
376
  }
355
377
 
356
378
  .super-settings-modal-close {
357
- display: block;
379
+ display: flex;
380
+ align-items: center;
381
+ justify-content: center;
358
382
  position: absolute;
359
- top: 0;
360
- right: 0;
361
- border: 0;
362
- padding: 1ex;
363
- color: var(--modal-control-color);
364
- font-size: 1.5rem;
365
- font-weight: 500;
383
+ top: 16px;
384
+ right: 16px;
385
+ width: 32px;
386
+ height: 32px;
387
+ border: 1px solid var(--border-light, #e2e5ea);
388
+ border-radius: 7px;
389
+ background: transparent;
390
+ cursor: pointer;
391
+ color: var(--text-tertiary, var(--modal-control-color));
392
+ font-size: 1.25rem;
393
+ font-weight: 400;
394
+ transition: all 0.1s ease;
395
+ padding: 0;
396
+ line-height: 1;
397
+ }
398
+
399
+ .super-settings-modal-close:hover {
400
+ background: var(--bg-code, #f0f2f5);
401
+ color: var(--text-secondary, var(--modal-control-color));
366
402
  }
367
403
 
368
404
  /* Screen Reader and Accessibility */
@@ -385,8 +421,13 @@
385
421
  .super-settings-sticky-top {
386
422
  position: sticky;
387
423
  top: 0;
388
- padding: 1rem;
389
- background-color: var(--table-header-bg-color);
424
+ padding: 16px 0 12px;
425
+ background-color: var(--bg-page, var(--table-header-bg-color));
426
+ z-index: 10;
427
+ display: flex;
428
+ align-items: center;
429
+ gap: 10px;
430
+ flex-wrap: wrap;
390
431
  }
391
432
 
392
433
  .super-settings-align-center {
@@ -402,34 +443,48 @@
402
443
  }
403
444
 
404
445
  .super-settings-text-muted {
405
- color: var(--muted-color) !important;
446
+ color: var(--text-tertiary, var(--muted-color)) !important;
406
447
  }
407
448
 
408
449
  /* Form Controls */
409
450
 
410
451
  .super-settings-form-control {
411
- font-family: inherit;
452
+ font-family: var(--font-ui, system-ui, -apple-system, sans-serif);
412
453
  margin: 0;
413
454
  overflow: visible;
414
455
  display: block;
415
456
  width: 100%;
416
- padding: .375rem .75rem;
417
- font-size: 1rem;
457
+ padding: 8px 12px;
458
+ font-size: 0.875rem;
418
459
  line-height: 1.5;
419
- color: var(--form-control-color);
420
- background-color: var(--form-control-bg-color);
460
+ color: var(--text-primary, var(--form-control-color));
461
+ background-color: var(--bg-card, var(--form-control-bg-color));
421
462
  background-clip: padding-box;
422
- border: 1px solid var(--form-control-border-color);
423
- border-radius: .25rem;
424
- transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
463
+ border: 1px solid var(--border-card, var(--form-control-border-color));
464
+ border-radius: 8px;
465
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
466
+ box-shadow: var(--shadow-card, none);
467
+ outline: none;
468
+ }
469
+
470
+ .super-settings-form-control:focus {
471
+ border-color: var(--accent, var(--primary-color));
472
+ box-shadow: 0 0 0 2px var(--accent-glow, rgba(13, 148, 136, 0.12));
425
473
  }
426
474
 
427
475
  .super-settings-form-control::placeholder {
428
- color: var(--form-control-placeholder-color);
476
+ color: var(--text-tertiary, var(--form-control-placeholder-color));
429
477
  }
430
478
 
431
479
  select.super-settings-form-control:not([size]):not([multiple]) {
432
480
  height: calc(2.25rem + 2px);
481
+ cursor: pointer;
482
+ -webkit-appearance: none;
483
+ appearance: none;
484
+ padding-inline-end: 28px;
485
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%239ca3af'/%3E%3C/svg%3E");
486
+ background-repeat: no-repeat;
487
+ background-position: right 10px center;
433
488
  }
434
489
 
435
490
  .super-settings-form-check {
@@ -462,32 +517,35 @@ select.super-settings-form-control:not([size]):not([multiple]) {
462
517
  .super-settings-card-edit .super-settings-card-description textarea {
463
518
  width: 100%;
464
519
  box-sizing: border-box;
465
- min-width: 0; /* Allow shrinking in grid */
520
+ min-width: 0;
466
521
  }
467
522
 
468
523
  /* Buttons */
469
524
 
470
525
  .super-settings-btn {
471
- display: inline-block;
526
+ display: inline-flex;
527
+ align-items: center;
528
+ gap: 6px;
472
529
  vertical-align: middle;
473
- padding: 0.375rem 0.75rem;
474
- border-radius: 0.375rem;
475
- color: var(--form-control-color);
476
- border: 1px solid var(--form-control-border-color);
477
- background-color: var(--form-control-bg-color);
530
+ padding: 8px 14px;
531
+ border-radius: 8px;
532
+ color: var(--text-primary, var(--form-control-color));
533
+ border: 1px solid var(--border-card, var(--form-control-border-color));
534
+ background-color: var(--bg-card, var(--form-control-bg-color));
478
535
  text-decoration: none;
479
536
  text-align: center;
480
- font-family: Arial, sans-serif;
481
- font-size: 1rem;
482
- font-weight: 400;
537
+ font-family: var(--font-ui, system-ui, -apple-system, sans-serif);
538
+ font-size: 0.8125rem;
539
+ font-weight: 500;
483
540
  line-height: 1.5;
484
541
  user-select: none;
485
542
  cursor: pointer;
486
- transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
543
+ box-shadow: var(--shadow-card, none);
487
544
  }
488
545
 
489
546
  .super-settings-btn:hover:not(:disabled) {
490
547
  background-color: var(--btn-hover-color);
548
+ border-color: var(--accent, var(--primary-color));
491
549
  }
492
550
 
493
551
  .super-settings-btn:active {
@@ -496,7 +554,7 @@ select.super-settings-form-control:not([size]):not([multiple]) {
496
554
  }
497
555
 
498
556
  .super-settings-btn:disabled {
499
- opacity: 0.8;
557
+ opacity: 0.5;
500
558
  cursor: not-allowed;
501
559
  }
502
560
 
@@ -513,3 +571,40 @@ select.super-settings-form-control:not([size]):not([multiple]) {
513
571
  .super-settings-btn-primary:disabled {
514
572
  opacity: 0.5;
515
573
  }
574
+
575
+ /* Read-only mode: hide all edit controls */
576
+ .super-settings[data-read-only="true"] #super-settings-add-setting,
577
+ .super-settings[data-read-only="true"] #super-settings-save-settings,
578
+ .super-settings[data-read-only="true"] #super-settings-discard-changes,
579
+ .super-settings[data-read-only="true"] .js-edit-setting,
580
+ .super-settings[data-read-only="true"] .js-remove-setting {
581
+ display: none !important;
582
+ }
583
+
584
+ /* Settings count */
585
+ .js-settings-count {
586
+ font-size: 0.75rem;
587
+ font-weight: 500;
588
+ color: var(--text-tertiary, var(--muted-color));
589
+ }
590
+
591
+ /* Flash message */
592
+ .js-flash {
593
+ font-size: 0.8125rem;
594
+ }
595
+
596
+ /* Card reveal animation */
597
+ @keyframes super-settings-card-reveal {
598
+ from {
599
+ opacity: 0.2;
600
+ transform: translateY(-6px);
601
+ }
602
+ to {
603
+ opacity: 1;
604
+ transform: translateY(0);
605
+ }
606
+ }
607
+
608
+ .super-settings-card-reveal {
609
+ animation: super-settings-card-reveal 0.25s ease-out;
610
+ }
@@ -13,7 +13,9 @@ module SuperSettings
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
15
  # preference will be used.
16
- def initialize(layout: nil, add_to_head: nil, api_base_url: nil, color_scheme: nil)
16
+ # @param read_only [Boolean] whether to render the application in read-only mode (edit controls hidden).
17
+ # @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)
17
19
  if layout
18
20
  layout = File.expand_path(File.join("application", "layout.html.erb"), __dir__) if layout == :default
19
21
  @layout = ERB.new(File.read(layout)) if layout
@@ -25,6 +27,8 @@ module SuperSettings
25
27
 
26
28
  @api_base_url = api_base_url
27
29
  @color_scheme = color_scheme&.to_sym
30
+ @read_only = !!read_only
31
+ @locale = locale || SuperSettings::MiniI18n::DEFAULT_LOCALE
28
32
  end
29
33
 
30
34
  # Render the web UI application HTML.
@@ -38,6 +42,17 @@ module SuperSettings
38
42
  html
39
43
  end
40
44
 
45
+ # Render the edit form HTML for a single setting.
46
+ #
47
+ # @return [String] the rendered HTML
48
+ def render_edit
49
+ template = ERB.new(File.read(File.expand_path(File.join("application", "edit.html.erb"), __dir__)))
50
+ html = template.result(binding)
51
+ html = render_layout { html } if @layout
52
+ html = html.html_safe if html.respond_to?(:html_safe)
53
+ html
54
+ end
55
+
41
56
  private
42
57
 
43
58
  def render_layout