odt-ui-rails 2.0.1 → 2.2.1
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/README.md +348 -22
- data/app/assets/stylesheets/odt_ui/styles.css +1222 -3090
- data/app/assets/stylesheets/odt_ui/theme.css +126 -0
- data/app/assets/stylesheets/odt_ui/tokens.css +189 -46
- data/app/javascript/controllers/odt_modal_controller.js +61 -0
- data/app/javascript/controllers/odt_toast_controller.js +40 -0
- data/lib/generators/odt/install_generator.rb +62 -4
- data/lib/generators/odt/templates/odt_modal_controller.js +61 -0
- data/lib/generators/odt/templates/odt_toast_controller.js +40 -0
- data/lib/odt_ui/helper.rb +892 -240
- data/lib/odt_ui/version.rb +1 -1
- data/sig/odt_ui.rbs +266 -61
- metadata +171 -4
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* odt_ui/theme.css
|
|
3
|
+
*
|
|
4
|
+
* Tailwind CSS v4 @theme configuration for ODT Design Tokens.
|
|
5
|
+
*
|
|
6
|
+
* Usage in application.tailwind.css / application.css:
|
|
7
|
+
* @import "tailwindcss";
|
|
8
|
+
* @import "odt_ui/tokens.css";
|
|
9
|
+
* @import "odt_ui/styles.css";
|
|
10
|
+
* @import "odt_ui/theme.css";
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
@theme {
|
|
14
|
+
/* Primary Colors */
|
|
15
|
+
--color-primary-0: hsl(240 78.3% 100%);
|
|
16
|
+
--color-primary-50: hsl(240 78.3% 95%);
|
|
17
|
+
--color-primary-100: hsl(240 78.3% 90%);
|
|
18
|
+
--color-primary-200: hsl(240 78.3% 85%);
|
|
19
|
+
--color-primary-300: hsl(240 78.3% 80%);
|
|
20
|
+
--color-primary-400: hsl(240 78.3% 75%);
|
|
21
|
+
--color-primary-500: hsl(240 78.3% 65%);
|
|
22
|
+
--color-primary-600: hsl(240 78.3% 60%);
|
|
23
|
+
--color-primary-700: hsl(240 78.3% 55%);
|
|
24
|
+
--color-primary-800: hsl(240 78.3% 45%);
|
|
25
|
+
--color-primary-900: hsl(240 78.3% 34.3%);
|
|
26
|
+
|
|
27
|
+
/* Secondary Colors */
|
|
28
|
+
--color-secondary-0: hsl(47 100% 100%);
|
|
29
|
+
--color-secondary-50: hsl(47 100% 95%);
|
|
30
|
+
--color-secondary-100: hsl(47 100% 85%);
|
|
31
|
+
--color-secondary-200: hsl(47 100% 80%);
|
|
32
|
+
--color-secondary-300: hsl(47 100% 75%);
|
|
33
|
+
--color-secondary-400: hsl(47 100% 70%);
|
|
34
|
+
--color-secondary-500: hsl(47 100% 65%);
|
|
35
|
+
--color-secondary-600: hsl(47 100% 60%);
|
|
36
|
+
--color-secondary-700: hsl(47 100% 55%);
|
|
37
|
+
--color-secondary-800: hsl(47 100% 50%);
|
|
38
|
+
--color-secondary-900: hsl(47 100% 45%);
|
|
39
|
+
|
|
40
|
+
/* Neutral Palette */
|
|
41
|
+
--color-neutral-0: hsl(0 0% 100%);
|
|
42
|
+
--color-neutral-50: hsl(240 10% 98%);
|
|
43
|
+
--color-neutral-100: hsl(240 10% 96%);
|
|
44
|
+
--color-neutral-200: hsl(240 9% 90%);
|
|
45
|
+
--color-neutral-300: hsl(240 8% 82%);
|
|
46
|
+
--color-neutral-400: hsl(240 8% 64%);
|
|
47
|
+
--color-neutral-500: hsl(240 7% 46%);
|
|
48
|
+
--color-neutral-600: hsl(240 7% 32%);
|
|
49
|
+
--color-neutral-700: hsl(240 8% 25%);
|
|
50
|
+
--color-neutral-800: hsl(240 10% 15%);
|
|
51
|
+
--color-neutral-900: hsl(240 12% 9%);
|
|
52
|
+
--color-neutral-950: hsl(240 14% 4%);
|
|
53
|
+
|
|
54
|
+
/* Semantic Colors */
|
|
55
|
+
--color-success: hsl(142 71% 45%);
|
|
56
|
+
--color-success-subtle: hsl(142 71% 96%);
|
|
57
|
+
--color-warning: hsl(38 92% 50%);
|
|
58
|
+
--color-warning-subtle: hsl(38 92% 96%);
|
|
59
|
+
--color-danger: hsl(0 84% 60%);
|
|
60
|
+
--color-danger-subtle: hsl(0 84% 97%);
|
|
61
|
+
--color-info: hsl(217 91% 60%);
|
|
62
|
+
--color-info-subtle: hsl(217 91% 97%);
|
|
63
|
+
|
|
64
|
+
/* Surfaces & Backgrounds */
|
|
65
|
+
--color-surface-base: hsl(0 0% 100%);
|
|
66
|
+
--color-surface: hsl(0 0% 100%);
|
|
67
|
+
--color-surface-muted: hsl(240 10% 98%);
|
|
68
|
+
--color-surface-subtle: hsl(240 10% 96%);
|
|
69
|
+
--color-surface-elevated: hsl(240 10% 98%);
|
|
70
|
+
--color-surface-primary: hsl(240 78.3% 65%);
|
|
71
|
+
--color-surface-secondary: hsl(47 100% 65%);
|
|
72
|
+
--color-surface-success: hsl(142 71% 96%);
|
|
73
|
+
--color-surface-warning: hsl(38 92% 96%);
|
|
74
|
+
--color-surface-danger: hsl(0 84% 97%);
|
|
75
|
+
--color-surface-info: hsl(217 91% 97%);
|
|
76
|
+
|
|
77
|
+
/* Foregrounds */
|
|
78
|
+
--color-fg-strong: hsl(240 10% 15%);
|
|
79
|
+
--color-fg: hsl(240 8% 25%);
|
|
80
|
+
--color-fg-muted: hsl(240 7% 46%);
|
|
81
|
+
--color-fg-subtle: hsl(240 8% 64%);
|
|
82
|
+
--color-fg-disabled: hsl(240 8% 82%);
|
|
83
|
+
|
|
84
|
+
--color-fg-inverse-strong: hsl(0 0% 100%);
|
|
85
|
+
--color-fg-inverse: hsl(240 10% 98%);
|
|
86
|
+
--color-fg-inverse-muted: hsl(240 10% 96%);
|
|
87
|
+
--color-fg-inverse-subtle: hsl(240 8% 82%);
|
|
88
|
+
--color-fg-inverse-disabled: hsl(240 8% 64%);
|
|
89
|
+
|
|
90
|
+
--color-fg-primary: hsl(240 78.3% 34.3%);
|
|
91
|
+
--color-fg-secondary: hsl(47 100% 45%);
|
|
92
|
+
|
|
93
|
+
--color-fg-success: hsl(142 71% 45%);
|
|
94
|
+
--color-fg-warning: hsl(38 92% 50%);
|
|
95
|
+
--color-fg-danger: hsl(0 84% 60%);
|
|
96
|
+
--color-fg-info: hsl(217 91% 60%);
|
|
97
|
+
|
|
98
|
+
--color-ring: hsl(240 78.3% 65%);
|
|
99
|
+
|
|
100
|
+
/* Lines & Borders */
|
|
101
|
+
--color-line: hsl(240 9% 90%);
|
|
102
|
+
--color-line-muted: hsl(240 10% 96%);
|
|
103
|
+
--color-line-strong: hsl(240 8% 82%);
|
|
104
|
+
--color-line-primary: hsl(240 78.3% 65%);
|
|
105
|
+
--color-line-success: hsl(142 71% 45%);
|
|
106
|
+
--color-line-warning: hsl(38 92% 50%);
|
|
107
|
+
--color-line-danger: hsl(0 84% 60%);
|
|
108
|
+
|
|
109
|
+
/* Radius */
|
|
110
|
+
--radius-xs: 0.125rem;
|
|
111
|
+
--radius-sm: 0.25rem;
|
|
112
|
+
--radius-md: 0.375rem;
|
|
113
|
+
--radius-lg: 0.5rem;
|
|
114
|
+
--radius-xl: 0.75rem;
|
|
115
|
+
--radius-2xl: 1rem;
|
|
116
|
+
--radius-3xl: 1.5rem;
|
|
117
|
+
--radius-4xl: 2rem;
|
|
118
|
+
--radius-full: 9999px;
|
|
119
|
+
|
|
120
|
+
/* Shadows */
|
|
121
|
+
--color-shadow: hsl(240 78.3% 70%);
|
|
122
|
+
--shadow-card: 0 8px 26px hsl(240 78.3% 70% / 0.10);
|
|
123
|
+
--shadow-dropdown: 0 8px 24px hsl(240 78.3% 70% / 0.12);
|
|
124
|
+
--shadow-modal: 0 16px 40px hsl(240 78.3% 70% / 0.16);
|
|
125
|
+
--shadow-popover: 0 24px 64px hsl(240 78.3% 70% / 0.20);
|
|
126
|
+
}
|
|
@@ -86,16 +86,44 @@
|
|
|
86
86
|
--color-fg-danger: var(--color-danger);
|
|
87
87
|
--color-fg-info: var(--color-info);
|
|
88
88
|
|
|
89
|
+
/* ==========================================================================
|
|
90
|
+
* Button & Solid Controls Foreground (Text & Icon on Solid Controls)
|
|
91
|
+
* ========================================================================== */
|
|
92
|
+
--color-btn-primary-fg: hsl(0 0% 100%);
|
|
93
|
+
--color-btn-secondary-fg: hsl(224 25% 6%);
|
|
94
|
+
--color-btn-surface-fg: var(--color-fg-strong);
|
|
95
|
+
--color-btn-muted-fg: var(--color-fg);
|
|
96
|
+
--color-btn-inverse-fg: var(--color-surface);
|
|
97
|
+
--color-btn-success-fg: hsl(0 0% 100%);
|
|
98
|
+
--color-btn-warning-fg: var(--color-fg-strong);
|
|
99
|
+
--color-btn-danger-fg: hsl(0 0% 100%);
|
|
100
|
+
--color-btn-info-fg: hsl(0 0% 100%);
|
|
101
|
+
|
|
102
|
+
/* Badge Foreground */
|
|
103
|
+
--color-badge-primary-fg: var(--color-btn-primary-fg);
|
|
104
|
+
--color-badge-secondary-fg: var(--color-btn-secondary-fg);
|
|
105
|
+
--color-badge-success-fg: var(--color-btn-success-fg);
|
|
106
|
+
--color-badge-warning-fg: var(--color-btn-warning-fg);
|
|
107
|
+
--color-badge-danger-fg: var(--color-btn-danger-fg);
|
|
108
|
+
--color-badge-info-fg: var(--color-btn-info-fg);
|
|
109
|
+
--color-badge-neutral-fg: var(--color-neutral-0);
|
|
110
|
+
|
|
111
|
+
/* Control (Checkbox / Radio / Switch) Tokens */
|
|
112
|
+
--color-control-checked-fg: hsl(0 0% 100%);
|
|
113
|
+
--color-control-checked-dark-fg: hsl(224 25% 6%);
|
|
114
|
+
--color-switch-thumb: var(--color-neutral-0);
|
|
115
|
+
|
|
89
116
|
/* ==========================================================================
|
|
90
117
|
* Focus Ring
|
|
91
118
|
* ========================================================================== */
|
|
92
|
-
--color-ring: var(--color-primary-
|
|
119
|
+
--color-ring: var(--color-primary-300);
|
|
93
120
|
}
|
|
94
121
|
|
|
95
122
|
:root {
|
|
96
123
|
/* ==========================================================================
|
|
97
124
|
* Surfaces & Backgrounds
|
|
98
125
|
* ========================================================================== */
|
|
126
|
+
--color-surface-base: var(--color-surface);
|
|
99
127
|
--color-surface: var(--color-neutral-0);
|
|
100
128
|
--color-surface-muted: var(--color-neutral-50);
|
|
101
129
|
--color-surface-subtle: var(--color-neutral-100);
|
|
@@ -253,50 +281,165 @@
|
|
|
253
281
|
:root[data-theme="dark"],
|
|
254
282
|
[data-theme="dark"],
|
|
255
283
|
.dark {
|
|
256
|
-
/*
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
--color-
|
|
260
|
-
--color-
|
|
261
|
-
--color-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
--color-
|
|
265
|
-
--color-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
--color-
|
|
269
|
-
--color-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
--color-
|
|
275
|
-
--color-
|
|
276
|
-
--color-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
--color-
|
|
280
|
-
--
|
|
281
|
-
--
|
|
282
|
-
--
|
|
283
|
-
--
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
--
|
|
291
|
-
--
|
|
292
|
-
--
|
|
293
|
-
--
|
|
294
|
-
--
|
|
295
|
-
--
|
|
296
|
-
--
|
|
297
|
-
--
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
--
|
|
284
|
+
/* ==========================================================================
|
|
285
|
+
* Primary Brand Colors (Dark Scale)
|
|
286
|
+
* ========================================================================== */
|
|
287
|
+
--color-primary-0: hsl(240 78.3% 10%);
|
|
288
|
+
--color-primary-50: hsla(240, 78.3%, 65%, 0.18);
|
|
289
|
+
--color-primary-100: hsla(240, 78.3%, 65%, 0.28);
|
|
290
|
+
--color-primary-200: hsl(240 78.3% 34.3%);
|
|
291
|
+
--color-primary-300: hsl(240 78.3% 45%);
|
|
292
|
+
--color-primary-400: hsl(240 78.3% 55%);
|
|
293
|
+
--color-primary-500: hsl(240 78.3% 65%);
|
|
294
|
+
--color-primary-600: hsl(240 78.3% 72%);
|
|
295
|
+
--color-primary-700: hsl(240 78.3% 80%);
|
|
296
|
+
--color-primary-800: hsl(240 78.3% 88%);
|
|
297
|
+
--color-primary-900: hsl(240 78.3% 96%);
|
|
298
|
+
|
|
299
|
+
/* ==========================================================================
|
|
300
|
+
* Secondary Brand Colors (Dark Scale)
|
|
301
|
+
* ========================================================================== */
|
|
302
|
+
--color-secondary-0: hsl(47 100% 10%);
|
|
303
|
+
--color-secondary-50: hsla(47, 100%, 60%, 0.16);
|
|
304
|
+
--color-secondary-100: hsla(47, 100%, 60%, 0.25);
|
|
305
|
+
--color-secondary-200: hsl(47 100% 30%);
|
|
306
|
+
--color-secondary-300: hsl(47 100% 40%);
|
|
307
|
+
--color-secondary-400: hsl(47 100% 50%);
|
|
308
|
+
--color-secondary-500: hsl(47 100% 60%);
|
|
309
|
+
--color-secondary-600: hsl(47 100% 68%);
|
|
310
|
+
--color-secondary-700: hsl(47 100% 75%);
|
|
311
|
+
--color-secondary-800: hsl(47 100% 82%);
|
|
312
|
+
--color-secondary-900: hsl(47 100% 90%);
|
|
313
|
+
|
|
314
|
+
/* ==========================================================================
|
|
315
|
+
* Neutral Palette (Dark Scale)
|
|
316
|
+
* ========================================================================== */
|
|
317
|
+
--color-neutral-0: hsl(224 25% 6%);
|
|
318
|
+
--color-neutral-50: hsl(224 20% 10%);
|
|
319
|
+
--color-neutral-100: hsl(224 16% 15%);
|
|
320
|
+
--color-neutral-200: hsl(224 14% 18%);
|
|
321
|
+
--color-neutral-300: hsl(224 14% 26%);
|
|
322
|
+
--color-neutral-400: hsl(215 14% 48%);
|
|
323
|
+
--color-neutral-500: hsl(215 16% 62%);
|
|
324
|
+
--color-neutral-600: hsl(215 18% 74%);
|
|
325
|
+
--color-neutral-700: hsl(215 20% 84%);
|
|
326
|
+
--color-neutral-800: hsl(215 22% 92%);
|
|
327
|
+
--color-neutral-900: hsl(215 24% 97%);
|
|
328
|
+
--color-neutral-950: hsl(0 0% 100%);
|
|
329
|
+
|
|
330
|
+
/* ==========================================================================
|
|
331
|
+
* Semantic Colors
|
|
332
|
+
* ========================================================================== */
|
|
333
|
+
--color-success: hsl(142 71% 45%);
|
|
334
|
+
--color-warning: hsl(38 92% 58%);
|
|
335
|
+
--color-danger: hsl(0 78% 64%);
|
|
336
|
+
--color-info: hsl(217 91% 64%);
|
|
337
|
+
|
|
338
|
+
/* Semantic surface tint */
|
|
339
|
+
--color-surface-success: hsl(152 68% 12%);
|
|
340
|
+
--color-surface-warning: hsl(38 92% 13%);
|
|
341
|
+
--color-surface-danger: hsl(0 78% 14%);
|
|
342
|
+
--color-surface-info: hsl(217 91% 14%);
|
|
343
|
+
|
|
344
|
+
/* ==========================================================================
|
|
345
|
+
* Surfaces & Backgrounds
|
|
346
|
+
* ========================================================================== */
|
|
347
|
+
--color-surface-base: var(--color-surface-elevated);
|
|
348
|
+
--color-surface: var(--color-neutral-0);
|
|
349
|
+
--color-surface-elevated: var(--color-neutral-50);
|
|
350
|
+
--color-surface-muted: hsl(224 22% 8%);
|
|
351
|
+
--color-surface-subtle: var(--color-neutral-100);
|
|
352
|
+
--color-surface-primary: var(--color-primary-500);
|
|
353
|
+
--color-surface-secondary: var(--color-secondary-500);
|
|
354
|
+
|
|
355
|
+
/* ==========================================================================
|
|
356
|
+
* Foreground (Text & Icon)
|
|
357
|
+
* ========================================================================== */
|
|
358
|
+
--color-fg-strong: var(--color-neutral-900);
|
|
359
|
+
--color-fg: var(--color-neutral-700);
|
|
360
|
+
--color-fg-muted: var(--color-neutral-500);
|
|
361
|
+
--color-fg-subtle: var(--color-neutral-400);
|
|
362
|
+
--color-fg-disabled: hsl(215 12% 32%);
|
|
363
|
+
|
|
364
|
+
/* Inverse */
|
|
365
|
+
--color-fg-inverse-strong: var(--color-neutral-0);
|
|
366
|
+
--color-fg-inverse: var(--color-neutral-50);
|
|
367
|
+
--color-fg-inverse-muted: var(--color-neutral-100);
|
|
368
|
+
--color-fg-inverse-subtle: var(--color-neutral-300);
|
|
369
|
+
--color-fg-inverse-disabled: var(--color-neutral-400);
|
|
370
|
+
|
|
371
|
+
/* Brand Foreground */
|
|
372
|
+
--color-fg-primary: var(--color-primary-600);
|
|
373
|
+
--color-fg-secondary: var(--color-secondary-600);
|
|
374
|
+
|
|
375
|
+
/* Semantic Foreground */
|
|
376
|
+
--color-fg-success: var(--color-success);
|
|
377
|
+
--color-fg-warning: var(--color-warning);
|
|
378
|
+
--color-fg-danger: var(--color-danger);
|
|
379
|
+
--color-fg-info: var(--color-info);
|
|
380
|
+
|
|
381
|
+
/* Focus Ring */
|
|
382
|
+
--color-ring: hsl(240, 42%, 39%);
|
|
383
|
+
|
|
384
|
+
/* ==========================================================================
|
|
385
|
+
* Borders & Lines
|
|
386
|
+
* ========================================================================== */
|
|
387
|
+
--color-line: var(--color-neutral-200);
|
|
388
|
+
--color-line-muted: var(--color-neutral-100);
|
|
389
|
+
--color-line-strong: hsl(224, 44%, 27%);
|
|
390
|
+
|
|
391
|
+
--color-line-primary: var(--color-primary-500);
|
|
392
|
+
--color-line-success: var(--color-success);
|
|
393
|
+
--color-line-warning: var(--color-warning);
|
|
394
|
+
--color-line-danger: var(--color-danger);
|
|
395
|
+
|
|
396
|
+
/* ==========================================================================
|
|
397
|
+
* Shadows & Depth Elevations
|
|
398
|
+
* ========================================================================== */
|
|
399
|
+
--color-shadow: hsl(0 0% 0%);
|
|
400
|
+
|
|
401
|
+
--shadow-card: 0 8px 26px hsl(0 0% 0% / 0.50);
|
|
402
|
+
--shadow-dropdown: 0 8px 24px hsl(0 0% 0% / 0.60);
|
|
403
|
+
--shadow-modal: 0 16px 40px hsl(0 0% 0% / 0.70);
|
|
404
|
+
--shadow-popover: 0 24px 64px hsl(0 0% 0% / 0.80);
|
|
405
|
+
|
|
406
|
+
/* ==========================================================================
|
|
407
|
+
* Gradients
|
|
408
|
+
* ========================================================================== */
|
|
409
|
+
--gradient-subtle: linear-gradient(to top right, var(--color-primary-50), var(--color-primary-0) 60%, var(--color-secondary-50));
|
|
410
|
+
--gradient-hero-primary: var(--gradient-subtle);
|
|
411
|
+
|
|
412
|
+
/* Vibrant accent gradient */
|
|
413
|
+
--gradient-vibrant: linear-gradient(to top right, var(--color-primary-200), var(--color-primary-50) 50%, var(--color-secondary-100));
|
|
414
|
+
--gradient-hero-vibrant: var(--gradient-vibrant);
|
|
415
|
+
|
|
416
|
+
/* Card surface gradients */
|
|
417
|
+
--gradient-card: linear-gradient(to bottom, hsla(240, 78.3%, 65%, 0.25), var(--color-neutral-50));
|
|
418
|
+
--gradient-primary-to-white: linear-gradient(to bottom, var(--color-primary-50), var(--color-surface));
|
|
419
|
+
--gradient-secondary-to-white: linear-gradient(to bottom, var(--color-secondary-50), var(--color-surface));
|
|
420
|
+
--gradient-primary-h: linear-gradient(to right, var(--color-primary-50), var(--color-surface));
|
|
421
|
+
--gradient-secondary-h: linear-gradient(to right, var(--color-secondary-50), var(--color-surface));
|
|
422
|
+
|
|
423
|
+
/* ==========================================================================
|
|
424
|
+
* Button & Solid Controls Foreground
|
|
425
|
+
* ========================================================================== */
|
|
426
|
+
--color-btn-surface-fg: var(--color-fg-strong);
|
|
427
|
+
--color-btn-muted-fg: var(--color-fg);
|
|
428
|
+
--color-btn-inverse-fg: var(--color-surface);
|
|
429
|
+
--color-btn-warning-fg: hsl(224 25% 6%);
|
|
430
|
+
--color-badge-neutral-fg: var(--color-neutral-0);
|
|
431
|
+
--color-switch-thumb: hsl(0 0% 100%);
|
|
432
|
+
|
|
433
|
+
/* ==========================================================================
|
|
434
|
+
* Frosted Glass Tokens
|
|
435
|
+
* ========================================================================== */
|
|
436
|
+
--frosted-surface-bg: hsl(224 25% 6% / 0.60);
|
|
437
|
+
--frosted-surface-border: hsl(224 14% 26% / 0.70);
|
|
438
|
+
--frosted-muted-bg: hsl(224 22% 8% / 0.60);
|
|
439
|
+
--frosted-muted-border: hsl(224 22% 8% / 0.70);
|
|
440
|
+
--frosted-subtle-bg: hsl(224 16% 15% / 0.60);
|
|
441
|
+
--frosted-subtle-border: hsl(224 16% 15% / 0.70);
|
|
442
|
+
--frosted-gradient-primary: linear-gradient(to bottom right, hsla(240, 78.3%, 65%, 0.18), hsl(224 25% 6% / 0.60));
|
|
443
|
+
--frosted-gradient-secondary: linear-gradient(to bottom right, hsla(47, 100%, 60%, 0.16), hsl(224 25% 6% / 0.60));
|
|
301
444
|
}
|
|
302
445
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["dialog"]
|
|
5
|
+
static values = {
|
|
6
|
+
open: { type: Boolean, default: false },
|
|
7
|
+
preventBackdropClose: { type: Boolean, default: false }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
connect() {
|
|
11
|
+
if (this.openValue) {
|
|
12
|
+
this.open()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
open(event) {
|
|
17
|
+
if (event) event.preventDefault()
|
|
18
|
+
|
|
19
|
+
this.element.classList.remove("hidden")
|
|
20
|
+
this.element.setAttribute("aria-hidden", "false")
|
|
21
|
+
this.element.classList.remove("odt-modal-overlay--exiting")
|
|
22
|
+
if (this.hasDialogTarget) {
|
|
23
|
+
this.dialogTarget.classList.remove("odt-modal--exiting")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
document.body.style.overflow = "hidden"
|
|
27
|
+
this.element.dispatchEvent(new CustomEvent("odt-modal:opened", { bubbles: true }))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
close(event) {
|
|
31
|
+
if (event) event.preventDefault()
|
|
32
|
+
|
|
33
|
+
this.element.classList.add("odt-modal-overlay--exiting")
|
|
34
|
+
if (this.hasDialogTarget) {
|
|
35
|
+
this.dialogTarget.classList.add("odt-modal--exiting")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
document.body.style.overflow = ""
|
|
39
|
+
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
this.element.classList.add("hidden")
|
|
42
|
+
this.element.classList.remove("odt-modal-overlay--exiting")
|
|
43
|
+
if (this.hasDialogTarget) {
|
|
44
|
+
this.dialogTarget.classList.remove("odt-modal--exiting")
|
|
45
|
+
}
|
|
46
|
+
this.element.setAttribute("aria-hidden", "true")
|
|
47
|
+
this.element.dispatchEvent(new CustomEvent("odt-modal:closed", { bubbles: true }))
|
|
48
|
+
}, 200)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
backdropClose(event) {
|
|
52
|
+
if (this.preventBackdropCloseValue) return
|
|
53
|
+
if (event.target === this.element) {
|
|
54
|
+
this.close(event)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
disconnect() {
|
|
59
|
+
document.body.style.overflow = ""
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static values = {
|
|
5
|
+
duration: { type: Number, default: 4000 }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
connect() {
|
|
9
|
+
this.startTimer()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
startTimer() {
|
|
13
|
+
if (this.durationValue > 0) {
|
|
14
|
+
this.timeout = setTimeout(() => this.dismiss(), this.durationValue)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pauseTimer() {
|
|
19
|
+
if (this.timeout) {
|
|
20
|
+
clearTimeout(this.timeout)
|
|
21
|
+
this.timeout = null
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
resumeTimer() {
|
|
26
|
+
this.startTimer()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
dismiss() {
|
|
30
|
+
this.pauseTimer()
|
|
31
|
+
this.element.classList.add("odt-toast--exiting")
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
this.element.remove()
|
|
34
|
+
}, 250)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
disconnect() {
|
|
38
|
+
this.pauseTimer()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -5,10 +5,11 @@ require "rails/generators/base"
|
|
|
5
5
|
module Odt
|
|
6
6
|
module Generators
|
|
7
7
|
class InstallGenerator < Rails::Generators::Base
|
|
8
|
-
desc "Configures ODT UI stylesheets for Rails application"
|
|
8
|
+
desc "Configures ODT UI standalone stylesheets, Tailwind theme, and RBS type signatures for Rails application"
|
|
9
9
|
|
|
10
10
|
def inject_stylesheets
|
|
11
11
|
css_candidates = [
|
|
12
|
+
"app/assets/tailwind/application.css",
|
|
12
13
|
"app/assets/stylesheets/application.tailwind.css",
|
|
13
14
|
"app/assets/stylesheets/application.css",
|
|
14
15
|
"app/assets/stylesheets/application.scss"
|
|
@@ -17,11 +18,68 @@ module Odt
|
|
|
17
18
|
target_css = css_candidates.find { |file| File.exist?(file) }
|
|
18
19
|
|
|
19
20
|
if target_css
|
|
20
|
-
|
|
21
|
+
existing_content = File.read(target_css)
|
|
22
|
+
|
|
23
|
+
if existing_content.include?("odt_ui")
|
|
24
|
+
say "ODT UI stylesheet imports already present in #{target_css}", :yellow
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
is_tailwind = target_css.include?("tailwind") || existing_content.include?("@import \"tailwindcss\"") || existing_content.include?("@import 'tailwindcss'")
|
|
29
|
+
|
|
30
|
+
imports = if is_tailwind
|
|
31
|
+
<<~CSS
|
|
32
|
+
|
|
33
|
+
/* ==========================================================================
|
|
34
|
+
* ODT Lightweight UI - Design Tokens, Standalone Styles & Tailwind Theme
|
|
35
|
+
* ========================================================================== */
|
|
36
|
+
@import "odt_ui/tokens.css";
|
|
37
|
+
@import "odt_ui/styles.css";
|
|
38
|
+
@import "odt_ui/theme.css";
|
|
39
|
+
CSS
|
|
40
|
+
else
|
|
41
|
+
<<~CSS
|
|
42
|
+
|
|
43
|
+
/* ==========================================================================
|
|
44
|
+
* ODT Lightweight UI - Design Tokens & Standalone Component Styles
|
|
45
|
+
* ========================================================================== */
|
|
46
|
+
@import "odt_ui/tokens.css";
|
|
47
|
+
@import "odt_ui/styles.css";
|
|
48
|
+
CSS
|
|
49
|
+
end
|
|
50
|
+
|
|
21
51
|
append_to_file target_css, imports
|
|
22
|
-
say "Added ODT CSS imports to #{target_css}", :green
|
|
52
|
+
say "Added ODT UI CSS imports to #{target_css}", :green
|
|
23
53
|
else
|
|
24
|
-
say "
|
|
54
|
+
say "No standard application stylesheet found.", :yellow
|
|
55
|
+
say "Please add the following to your application stylesheet or layout:", :yellow
|
|
56
|
+
say %( @import "odt_ui/tokens.css";\n @import "odt_ui/styles.css";\n), :cyan
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def copy_rbs_signature
|
|
61
|
+
source = File.expand_path("../../../../../sig/odt_ui.rbs", __dir__)
|
|
62
|
+
return unless File.exist?(source)
|
|
63
|
+
|
|
64
|
+
empty_directory "sig"
|
|
65
|
+
copy_file source, "sig/odt_ui.rbs"
|
|
66
|
+
say "Copied sig/odt_ui.rbs for Ruby LSP / Solargraph support", :green
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def copy_stimulus_controller
|
|
70
|
+
toast_source = File.expand_path("templates/odt_toast_controller.js", __dir__)
|
|
71
|
+
modal_source = File.expand_path("templates/odt_modal_controller.js", __dir__)
|
|
72
|
+
|
|
73
|
+
if File.directory?("app/javascript/controllers") || File.directory?("app/javascript")
|
|
74
|
+
empty_directory "app/javascript/controllers"
|
|
75
|
+
if File.exist?(toast_source)
|
|
76
|
+
copy_file toast_source, "app/javascript/controllers/odt_toast_controller.js"
|
|
77
|
+
say "Copied app/javascript/controllers/odt_toast_controller.js", :green
|
|
78
|
+
end
|
|
79
|
+
if File.exist?(modal_source)
|
|
80
|
+
copy_file modal_source, "app/javascript/controllers/odt_modal_controller.js"
|
|
81
|
+
say "Copied app/javascript/controllers/odt_modal_controller.js", :green
|
|
82
|
+
end
|
|
25
83
|
end
|
|
26
84
|
end
|
|
27
85
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["dialog"]
|
|
5
|
+
static values = {
|
|
6
|
+
open: { type: Boolean, default: false },
|
|
7
|
+
preventBackdropClose: { type: Boolean, default: false }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
connect() {
|
|
11
|
+
if (this.openValue) {
|
|
12
|
+
this.open()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
open(event) {
|
|
17
|
+
if (event) event.preventDefault()
|
|
18
|
+
|
|
19
|
+
this.element.classList.remove("hidden")
|
|
20
|
+
this.element.setAttribute("aria-hidden", "false")
|
|
21
|
+
this.element.classList.remove("odt-modal-overlay--exiting")
|
|
22
|
+
if (this.hasDialogTarget) {
|
|
23
|
+
this.dialogTarget.classList.remove("odt-modal--exiting")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
document.body.style.overflow = "hidden"
|
|
27
|
+
this.element.dispatchEvent(new CustomEvent("odt-modal:opened", { bubbles: true }))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
close(event) {
|
|
31
|
+
if (event) event.preventDefault()
|
|
32
|
+
|
|
33
|
+
this.element.classList.add("odt-modal-overlay--exiting")
|
|
34
|
+
if (this.hasDialogTarget) {
|
|
35
|
+
this.dialogTarget.classList.add("odt-modal--exiting")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
document.body.style.overflow = ""
|
|
39
|
+
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
this.element.classList.add("hidden")
|
|
42
|
+
this.element.classList.remove("odt-modal-overlay--exiting")
|
|
43
|
+
if (this.hasDialogTarget) {
|
|
44
|
+
this.dialogTarget.classList.remove("odt-modal--exiting")
|
|
45
|
+
}
|
|
46
|
+
this.element.setAttribute("aria-hidden", "true")
|
|
47
|
+
this.element.dispatchEvent(new CustomEvent("odt-modal:closed", { bubbles: true }))
|
|
48
|
+
}, 200)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
backdropClose(event) {
|
|
52
|
+
if (this.preventBackdropCloseValue) return
|
|
53
|
+
if (event.target === this.element) {
|
|
54
|
+
this.close(event)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
disconnect() {
|
|
59
|
+
document.body.style.overflow = ""
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static values = {
|
|
5
|
+
duration: { type: Number, default: 4000 }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
connect() {
|
|
9
|
+
this.startTimer()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
startTimer() {
|
|
13
|
+
if (this.durationValue > 0) {
|
|
14
|
+
this.timeout = setTimeout(() => this.dismiss(), this.durationValue)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pauseTimer() {
|
|
19
|
+
if (this.timeout) {
|
|
20
|
+
clearTimeout(this.timeout)
|
|
21
|
+
this.timeout = null
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
resumeTimer() {
|
|
26
|
+
this.startTimer()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
dismiss() {
|
|
30
|
+
this.pauseTimer()
|
|
31
|
+
this.element.classList.add("odt-toast--exiting")
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
this.element.remove()
|
|
34
|
+
}, 250)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
disconnect() {
|
|
38
|
+
this.pauseTimer()
|
|
39
|
+
}
|
|
40
|
+
}
|