bh 6.1.4 → 6.3.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 +50 -0
- data/README.md +103 -15
- data/app/javascript/bh/bookmark_controller.js +97 -0
- data/app/javascript/bh/clear_controller.js +22 -0
- data/app/javascript/bh/combobox/menu.js +93 -0
- data/app/javascript/bh/combobox_controller.js +82 -0
- data/app/javascript/bh/confirm.js +100 -0
- data/app/javascript/bh/density_controller.js +21 -0
- data/app/javascript/bh/deselect_controller.js +37 -0
- data/app/javascript/bh/flash.js +35 -0
- data/app/javascript/bh/limit_controller.js +23 -0
- data/app/javascript/bh/map/loader.js +20 -0
- data/app/javascript/bh/map_controller.js +88 -0
- data/app/javascript/bh/otp/slots.js +27 -0
- data/app/javascript/bh/otp_controller.js +98 -0
- data/app/javascript/bh/phone_controller.js +89 -0
- data/app/javascript/bh/placeholder_controller.js +28 -0
- data/app/javascript/bh/relative_time_controller.js +45 -0
- data/app/javascript/bh/require_controller.js +18 -0
- data/app/javascript/bh/reveal_controller.js +16 -0
- data/app/javascript/bh/scheme_controller.js +99 -0
- data/app/javascript/bh/search_controller.js +78 -0
- data/app/javascript/bh/shortcuts_controller.js +42 -0
- data/app/javascript/bh/sortable_controller.js +84 -0
- data/app/javascript/bh/thread_controller.js +47 -0
- data/app/javascript/bh/timezone_controller.js +27 -0
- data/app/javascript/bh/toast_controller.js +35 -0
- data/app/javascript/bh/tooltip_controller.js +23 -0
- data/app/javascript/bh/written.js +20 -0
- data/app/javascript/bh/written_controller.js +28 -0
- data/app/javascript/bh.js +60 -0
- data/app/stylesheets/bh/base.css +27 -0
- data/app/stylesheets/bh/chat.css +77 -0
- data/app/stylesheets/bh/flow.css +94 -0
- data/app/stylesheets/bh/map.css +3 -0
- data/app/stylesheets/bh/pin.css +34 -0
- data/app/stylesheets/bh/search.css +60 -0
- data/app/stylesheets/bh/shell.css +202 -0
- data/app/stylesheets/bh/table.css +130 -0
- data/app/stylesheets/bh/values.css +41 -0
- data/app/stylesheets/bh.css +13 -0
- data/app/stylesheets/theme/bootstrap.css +10 -0
- data/app/stylesheets/theme/dawn.css +189 -0
- data/app/stylesheets/theme/dracula.css +189 -0
- data/app/stylesheets/theme/gruvbox.css +189 -0
- data/app/stylesheets/theme/monokai.css +190 -0
- data/app/stylesheets/theme/nord.css +189 -0
- data/app/stylesheets/theme/one_dark.css +189 -0
- data/app/stylesheets/theme/solarized.css +188 -0
- data/app/stylesheets/theme/tokyo_night.css +189 -0
- data/build.mjs +21 -0
- data/config/locales/bh.en.yml +13 -0
- data/lib/bh/engine.rb +21 -6
- data/lib/bh/form_builder/comboboxes.rb +38 -0
- data/lib/bh/form_builder/controls.rb +67 -0
- data/lib/bh/form_builder/pins.rb +30 -0
- data/lib/bh/form_builder.rb +96 -0
- data/lib/bh/helpers/chats/asides.rb +49 -0
- data/lib/bh/helpers/chats/asks.rb +41 -0
- data/lib/bh/helpers/chats.rb +42 -0
- data/lib/bh/helpers/dialogs.rb +47 -0
- data/lib/bh/helpers/flows.rb +49 -0
- data/lib/bh/helpers/heads.rb +27 -0
- data/lib/bh/helpers/notices.rb +55 -0
- data/lib/bh/helpers.rb +12 -0
- data/lib/bh/message.rb +11 -0
- data/lib/bh/version.rb +2 -3
- data/lib/bh.rb +8 -6
- data/package.json +20 -0
- data/public/bh/css/bh.css +1 -0
- data/public/bh/js/bh.js +152 -0
- data/public/bh/theme/bootstrap.css +10 -0
- data/public/bh/theme/dawn.css +189 -0
- data/public/bh/theme/dracula.css +189 -0
- data/public/bh/theme/gruvbox.css +189 -0
- data/public/bh/theme/monokai.css +190 -0
- data/public/bh/theme/nord.css +189 -0
- data/public/bh/theme/one_dark.css +189 -0
- data/public/bh/theme/solarized.css +188 -0
- data/public/bh/theme/tokyo_night.css +189 -0
- data/vendor/bootstrap.bundle.min.js +9 -0
- data/vendor/bootstrap.min.css +2 -0
- metadata +119 -23
- data/.gitignore +0 -23
- data/.rspec +0 -3
- data/.travis.yml +0 -15
- data/.yardopts +0 -3
- data/Gemfile +0 -4
- data/app/assets/stylesheets/bh.css +0 -29
- data/app/javascript/controllers/bh/theme_controller.js +0 -16
- data/app/javascript/controllers/phone_controller.js +0 -33
- data/app/javascript/controllers/require_controller.js +0 -20
- data/app/javascript/controllers/submit_controller.js +0 -24
- data/app/views/bh/_grid.html.erb +0 -6
- data/app/views/bh/_table.html.erb +0 -44
- data/bh.gemspec +0 -19
- data/lib/bh/bootstrap_helpers.rb +0 -137
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/* Solarized, Ethan Schoonover — https://ethanschoonover.com/solarized/
|
|
2
|
+
base3 is the light page and base03 the dark one, both Solarized itself.
|
|
3
|
+
yellow serves brown, the warmest tone Solarized has.
|
|
4
|
+
|
|
5
|
+
Bootstrap builds a family by mixing one base toward `--bs-white` below
|
|
6
|
+
the 500 step and toward `--bs-black` above it, and inlines that base
|
|
7
|
+
into all thirteen — so a palette restates the thirteen rather than the
|
|
8
|
+
one. Upstream's order and upstream's shapes with only the base swapped,
|
|
9
|
+
so a later Bootstrap diffs against this file. */
|
|
10
|
+
:root {
|
|
11
|
+
/* The page, and the two colors every ramp below is mixed with.
|
|
12
|
+
`--bs-bg-body` reads `--bs-white` in light mode and `--bs-gray-975` in
|
|
13
|
+
dark, so repainting these two is what moves the page itself. */
|
|
14
|
+
--bs-white: #fdf6e3;
|
|
15
|
+
--bs-black: #002b36;
|
|
16
|
+
|
|
17
|
+
/* The neutrals, which every surface, border and text token Bootstrap ships
|
|
18
|
+
derives from. */
|
|
19
|
+
--bs-gray-025: color-mix(in lab, var(--bs-white) 94%, #839496);
|
|
20
|
+
--bs-gray-050: color-mix(in lab, var(--bs-white) 90%, #839496);
|
|
21
|
+
--bs-gray-100: color-mix(in lab, var(--bs-white) 80%, #839496);
|
|
22
|
+
--bs-gray-200: color-mix(in lab, var(--bs-white) 60%, #839496);
|
|
23
|
+
--bs-gray-300: color-mix(in lab, var(--bs-white) 40%, #839496);
|
|
24
|
+
--bs-gray-400: color-mix(in lab, var(--bs-white) 20%, #839496);
|
|
25
|
+
--bs-gray-500: #839496;
|
|
26
|
+
--bs-gray-600: color-mix(in lab, var(--bs-black) 16%, #839496);
|
|
27
|
+
--bs-gray-700: color-mix(in lab, var(--bs-black) 32%, #839496);
|
|
28
|
+
--bs-gray-800: color-mix(in lab, var(--bs-black) 48%, #839496);
|
|
29
|
+
--bs-gray-900: color-mix(in lab, var(--bs-black) 64%, #839496);
|
|
30
|
+
--bs-gray-950: color-mix(in lab, var(--bs-black) 76%, #839496);
|
|
31
|
+
--bs-gray-975: color-mix(in lab, var(--bs-black) 88%, #839496);
|
|
32
|
+
|
|
33
|
+
--bs-blue-025: color-mix(in lab, var(--bs-white) 94%, #268bd2);
|
|
34
|
+
--bs-blue-050: color-mix(in lab, var(--bs-white) 90%, #268bd2);
|
|
35
|
+
--bs-blue-100: color-mix(in lab, var(--bs-white) 80%, #268bd2);
|
|
36
|
+
--bs-blue-200: color-mix(in lab, var(--bs-white) 60%, #268bd2);
|
|
37
|
+
--bs-blue-300: color-mix(in lab, var(--bs-white) 40%, #268bd2);
|
|
38
|
+
--bs-blue-400: color-mix(in lab, var(--bs-white) 20%, #268bd2);
|
|
39
|
+
--bs-blue-500: #268bd2;
|
|
40
|
+
--bs-blue-600: color-mix(in lab, var(--bs-black) 16%, #268bd2);
|
|
41
|
+
--bs-blue-700: color-mix(in lab, var(--bs-black) 32%, #268bd2);
|
|
42
|
+
--bs-blue-800: color-mix(in lab, var(--bs-black) 48%, #268bd2);
|
|
43
|
+
--bs-blue-900: color-mix(in lab, var(--bs-black) 64%, #268bd2);
|
|
44
|
+
--bs-blue-950: color-mix(in lab, var(--bs-black) 76%, #268bd2);
|
|
45
|
+
--bs-blue-975: color-mix(in lab, var(--bs-black) 88%, #268bd2);
|
|
46
|
+
|
|
47
|
+
--bs-brown-025: color-mix(in lab, var(--bs-white) 94%, #b58900);
|
|
48
|
+
--bs-brown-050: color-mix(in lab, var(--bs-white) 90%, #b58900);
|
|
49
|
+
--bs-brown-100: color-mix(in lab, var(--bs-white) 80%, #b58900);
|
|
50
|
+
--bs-brown-200: color-mix(in lab, var(--bs-white) 60%, #b58900);
|
|
51
|
+
--bs-brown-300: color-mix(in lab, var(--bs-white) 40%, #b58900);
|
|
52
|
+
--bs-brown-400: color-mix(in lab, var(--bs-white) 20%, #b58900);
|
|
53
|
+
--bs-brown-500: #b58900;
|
|
54
|
+
--bs-brown-600: color-mix(in lab, var(--bs-black) 16%, #b58900);
|
|
55
|
+
--bs-brown-700: color-mix(in lab, var(--bs-black) 32%, #b58900);
|
|
56
|
+
--bs-brown-800: color-mix(in lab, var(--bs-black) 48%, #b58900);
|
|
57
|
+
--bs-brown-900: color-mix(in lab, var(--bs-black) 64%, #b58900);
|
|
58
|
+
--bs-brown-950: color-mix(in lab, var(--bs-black) 76%, #b58900);
|
|
59
|
+
--bs-brown-975: color-mix(in lab, var(--bs-black) 88%, #b58900);
|
|
60
|
+
|
|
61
|
+
--bs-cyan-025: color-mix(in lab, var(--bs-white) 94%, #2aa198);
|
|
62
|
+
--bs-cyan-050: color-mix(in lab, var(--bs-white) 90%, #2aa198);
|
|
63
|
+
--bs-cyan-100: color-mix(in lab, var(--bs-white) 80%, #2aa198);
|
|
64
|
+
--bs-cyan-200: color-mix(in lab, var(--bs-white) 60%, #2aa198);
|
|
65
|
+
--bs-cyan-300: color-mix(in lab, var(--bs-white) 40%, #2aa198);
|
|
66
|
+
--bs-cyan-400: color-mix(in lab, var(--bs-white) 20%, #2aa198);
|
|
67
|
+
--bs-cyan-500: #2aa198;
|
|
68
|
+
--bs-cyan-600: color-mix(in lab, var(--bs-black) 16%, #2aa198);
|
|
69
|
+
--bs-cyan-700: color-mix(in lab, var(--bs-black) 32%, #2aa198);
|
|
70
|
+
--bs-cyan-800: color-mix(in lab, var(--bs-black) 48%, #2aa198);
|
|
71
|
+
--bs-cyan-900: color-mix(in lab, var(--bs-black) 64%, #2aa198);
|
|
72
|
+
--bs-cyan-950: color-mix(in lab, var(--bs-black) 76%, #2aa198);
|
|
73
|
+
--bs-cyan-975: color-mix(in lab, var(--bs-black) 88%, #2aa198);
|
|
74
|
+
|
|
75
|
+
--bs-green-025: color-mix(in lab, var(--bs-white) 94%, #859900);
|
|
76
|
+
--bs-green-050: color-mix(in lab, var(--bs-white) 90%, #859900);
|
|
77
|
+
--bs-green-100: color-mix(in lab, var(--bs-white) 80%, #859900);
|
|
78
|
+
--bs-green-200: color-mix(in lab, var(--bs-white) 60%, #859900);
|
|
79
|
+
--bs-green-300: color-mix(in lab, var(--bs-white) 40%, #859900);
|
|
80
|
+
--bs-green-400: color-mix(in lab, var(--bs-white) 20%, #859900);
|
|
81
|
+
--bs-green-500: #859900;
|
|
82
|
+
--bs-green-600: color-mix(in lab, var(--bs-black) 16%, #859900);
|
|
83
|
+
--bs-green-700: color-mix(in lab, var(--bs-black) 32%, #859900);
|
|
84
|
+
--bs-green-800: color-mix(in lab, var(--bs-black) 48%, #859900);
|
|
85
|
+
--bs-green-900: color-mix(in lab, var(--bs-black) 64%, #859900);
|
|
86
|
+
--bs-green-950: color-mix(in lab, var(--bs-black) 76%, #859900);
|
|
87
|
+
--bs-green-975: color-mix(in lab, var(--bs-black) 88%, #859900);
|
|
88
|
+
|
|
89
|
+
--bs-orange-025: color-mix(in lab, var(--bs-white) 94%, #cb4b16);
|
|
90
|
+
--bs-orange-050: color-mix(in lab, var(--bs-white) 90%, #cb4b16);
|
|
91
|
+
--bs-orange-100: color-mix(in lab, var(--bs-white) 80%, #cb4b16);
|
|
92
|
+
--bs-orange-200: color-mix(in lab, var(--bs-white) 60%, #cb4b16);
|
|
93
|
+
--bs-orange-300: color-mix(in lab, var(--bs-white) 40%, #cb4b16);
|
|
94
|
+
--bs-orange-400: color-mix(in lab, var(--bs-white) 20%, #cb4b16);
|
|
95
|
+
--bs-orange-500: #cb4b16;
|
|
96
|
+
--bs-orange-600: color-mix(in lab, var(--bs-black) 16%, #cb4b16);
|
|
97
|
+
--bs-orange-700: color-mix(in lab, var(--bs-black) 32%, #cb4b16);
|
|
98
|
+
--bs-orange-800: color-mix(in lab, var(--bs-black) 48%, #cb4b16);
|
|
99
|
+
--bs-orange-900: color-mix(in lab, var(--bs-black) 64%, #cb4b16);
|
|
100
|
+
--bs-orange-950: color-mix(in lab, var(--bs-black) 76%, #cb4b16);
|
|
101
|
+
--bs-orange-975: color-mix(in lab, var(--bs-black) 88%, #cb4b16);
|
|
102
|
+
|
|
103
|
+
--bs-pink-025: color-mix(in lab, var(--bs-white) 94%, #d33682);
|
|
104
|
+
--bs-pink-050: color-mix(in lab, var(--bs-white) 90%, #d33682);
|
|
105
|
+
--bs-pink-100: color-mix(in lab, var(--bs-white) 80%, #d33682);
|
|
106
|
+
--bs-pink-200: color-mix(in lab, var(--bs-white) 60%, #d33682);
|
|
107
|
+
--bs-pink-300: color-mix(in lab, var(--bs-white) 40%, #d33682);
|
|
108
|
+
--bs-pink-400: color-mix(in lab, var(--bs-white) 20%, #d33682);
|
|
109
|
+
--bs-pink-500: #d33682;
|
|
110
|
+
--bs-pink-600: color-mix(in lab, var(--bs-black) 16%, #d33682);
|
|
111
|
+
--bs-pink-700: color-mix(in lab, var(--bs-black) 32%, #d33682);
|
|
112
|
+
--bs-pink-800: color-mix(in lab, var(--bs-black) 48%, #d33682);
|
|
113
|
+
--bs-pink-900: color-mix(in lab, var(--bs-black) 64%, #d33682);
|
|
114
|
+
--bs-pink-950: color-mix(in lab, var(--bs-black) 76%, #d33682);
|
|
115
|
+
--bs-pink-975: color-mix(in lab, var(--bs-black) 88%, #d33682);
|
|
116
|
+
|
|
117
|
+
--bs-purple-025: color-mix(in lab, var(--bs-white) 94%, #6c71c4);
|
|
118
|
+
--bs-purple-050: color-mix(in lab, var(--bs-white) 90%, #6c71c4);
|
|
119
|
+
--bs-purple-100: color-mix(in lab, var(--bs-white) 80%, #6c71c4);
|
|
120
|
+
--bs-purple-200: color-mix(in lab, var(--bs-white) 60%, #6c71c4);
|
|
121
|
+
--bs-purple-300: color-mix(in lab, var(--bs-white) 40%, #6c71c4);
|
|
122
|
+
--bs-purple-400: color-mix(in lab, var(--bs-white) 20%, #6c71c4);
|
|
123
|
+
--bs-purple-500: #6c71c4;
|
|
124
|
+
--bs-purple-600: color-mix(in lab, var(--bs-black) 16%, #6c71c4);
|
|
125
|
+
--bs-purple-700: color-mix(in lab, var(--bs-black) 32%, #6c71c4);
|
|
126
|
+
--bs-purple-800: color-mix(in lab, var(--bs-black) 48%, #6c71c4);
|
|
127
|
+
--bs-purple-900: color-mix(in lab, var(--bs-black) 64%, #6c71c4);
|
|
128
|
+
--bs-purple-950: color-mix(in lab, var(--bs-black) 76%, #6c71c4);
|
|
129
|
+
--bs-purple-975: color-mix(in lab, var(--bs-black) 88%, #6c71c4);
|
|
130
|
+
|
|
131
|
+
--bs-red-025: color-mix(in lab, var(--bs-white) 94%, #dc322f);
|
|
132
|
+
--bs-red-050: color-mix(in lab, var(--bs-white) 90%, #dc322f);
|
|
133
|
+
--bs-red-100: color-mix(in lab, var(--bs-white) 80%, #dc322f);
|
|
134
|
+
--bs-red-200: color-mix(in lab, var(--bs-white) 60%, #dc322f);
|
|
135
|
+
--bs-red-300: color-mix(in lab, var(--bs-white) 40%, #dc322f);
|
|
136
|
+
--bs-red-400: color-mix(in lab, var(--bs-white) 20%, #dc322f);
|
|
137
|
+
--bs-red-500: #dc322f;
|
|
138
|
+
--bs-red-600: color-mix(in lab, var(--bs-black) 16%, #dc322f);
|
|
139
|
+
--bs-red-700: color-mix(in lab, var(--bs-black) 32%, #dc322f);
|
|
140
|
+
--bs-red-800: color-mix(in lab, var(--bs-black) 48%, #dc322f);
|
|
141
|
+
--bs-red-900: color-mix(in lab, var(--bs-black) 64%, #dc322f);
|
|
142
|
+
--bs-red-950: color-mix(in lab, var(--bs-black) 76%, #dc322f);
|
|
143
|
+
--bs-red-975: color-mix(in lab, var(--bs-black) 88%, #dc322f);
|
|
144
|
+
|
|
145
|
+
--bs-yellow-025: color-mix(in lab, var(--bs-white) 94%, #b58900);
|
|
146
|
+
--bs-yellow-050: color-mix(in lab, var(--bs-white) 90%, #b58900);
|
|
147
|
+
--bs-yellow-100: color-mix(in lab, var(--bs-white) 80%, #b58900);
|
|
148
|
+
--bs-yellow-200: color-mix(in lab, var(--bs-white) 60%, #b58900);
|
|
149
|
+
--bs-yellow-300: color-mix(in lab, var(--bs-white) 40%, #b58900);
|
|
150
|
+
--bs-yellow-400: color-mix(in lab, var(--bs-white) 20%, #b58900);
|
|
151
|
+
--bs-yellow-500: #b58900;
|
|
152
|
+
--bs-yellow-600: color-mix(in lab, var(--bs-black) 16%, #b58900);
|
|
153
|
+
--bs-yellow-700: color-mix(in lab, var(--bs-black) 32%, #b58900);
|
|
154
|
+
--bs-yellow-800: color-mix(in lab, var(--bs-black) 48%, #b58900);
|
|
155
|
+
--bs-yellow-900: color-mix(in lab, var(--bs-black) 64%, #b58900);
|
|
156
|
+
--bs-yellow-950: color-mix(in lab, var(--bs-black) 76%, #b58900);
|
|
157
|
+
--bs-yellow-975: color-mix(in lab, var(--bs-black) 88%, #b58900);
|
|
158
|
+
|
|
159
|
+
/* Text, stated rather than left to the ramp. Bootstrap pairs a low step as
|
|
160
|
+
a light surface with that same step as dark-mode text, which a palette
|
|
161
|
+
built for its own contrast does not agree with. */
|
|
162
|
+
--bs-fg-1: light-dark(#073642, #eee8d5);
|
|
163
|
+
--bs-fg-body: light-dark(#586e75, #93a1a1);
|
|
164
|
+
--bs-fg-2: light-dark(#657b83, #839496);
|
|
165
|
+
|
|
166
|
+
/* The label a solid fill carries, for the four families Bootstrap has
|
|
167
|
+
spent on a meaning and this palette has repainted. Upstream's own shape:
|
|
168
|
+
it gives warning and info a dark label for the same reason. */
|
|
169
|
+
--bs-danger-contrast: var(--bs-white);
|
|
170
|
+
--bs-success-contrast: var(--bs-gray-975);
|
|
171
|
+
--bs-warning-contrast: var(--bs-gray-975);
|
|
172
|
+
--bs-info-contrast: var(--bs-gray-975);
|
|
173
|
+
|
|
174
|
+
/* The accent this palette leads with, as the primary color: the same nine
|
|
175
|
+
`_color.html.erb` writes, from blue and the label that reads on it. Here
|
|
176
|
+
rather than only in the page because a reader may swap this file for
|
|
177
|
+
another one, and the primary has to travel with it. A host naming its
|
|
178
|
+
own color still wins, its block coming after this file. */
|
|
179
|
+
--bs-primary-base: var(--bs-blue-500);
|
|
180
|
+
--bs-primary-fg: light-dark(var(--bs-blue-600), var(--bs-blue-400));
|
|
181
|
+
--bs-primary-fg-emphasis: light-dark(var(--bs-blue-800), var(--bs-blue-200));
|
|
182
|
+
--bs-primary-bg: var(--bs-blue-500);
|
|
183
|
+
--bs-primary-bg-subtle: light-dark(var(--bs-blue-100), var(--bs-blue-900));
|
|
184
|
+
--bs-primary-bg-muted: light-dark(var(--bs-blue-200), var(--bs-blue-800));
|
|
185
|
+
--bs-primary-border: light-dark(var(--bs-blue-300), var(--bs-blue-600));
|
|
186
|
+
--bs-primary-focus-ring: light-dark(color-mix(in oklch, var(--bs-blue-500) 50%, var(--bs-bg-body)), color-mix(in oklch, var(--bs-blue-500) 75%, var(--bs-bg-body)));
|
|
187
|
+
--bs-primary-contrast: var(--bs-gray-975);
|
|
188
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/* Tokyo Night, enkia — https://github.com/enkia/tokyo-night-vscode-theme
|
|
2
|
+
Tokyo Night Day is the light page and Tokyo Night's own the dark one.
|
|
3
|
+
its magenta serves purple and pink, its orange serves brown. The mid
|
|
4
|
+
neutral is derived.
|
|
5
|
+
|
|
6
|
+
Bootstrap builds a family by mixing one base toward `--bs-white` below
|
|
7
|
+
the 500 step and toward `--bs-black` above it, and inlines that base
|
|
8
|
+
into all thirteen — so a palette restates the thirteen rather than the
|
|
9
|
+
one. Upstream's order and upstream's shapes with only the base swapped,
|
|
10
|
+
so a later Bootstrap diffs against this file. */
|
|
11
|
+
:root {
|
|
12
|
+
/* The page, and the two colors every ramp below is mixed with.
|
|
13
|
+
`--bs-bg-body` reads `--bs-white` in light mode and `--bs-gray-975` in
|
|
14
|
+
dark, so repainting these two is what moves the page itself. */
|
|
15
|
+
--bs-white: #e1e2e7;
|
|
16
|
+
--bs-black: #1a1b26;
|
|
17
|
+
|
|
18
|
+
/* The neutrals, which every surface, border and text token Bootstrap ships
|
|
19
|
+
derives from. */
|
|
20
|
+
--bs-gray-025: color-mix(in lab, var(--bs-white) 94%, #8189a8);
|
|
21
|
+
--bs-gray-050: color-mix(in lab, var(--bs-white) 90%, #8189a8);
|
|
22
|
+
--bs-gray-100: color-mix(in lab, var(--bs-white) 80%, #8189a8);
|
|
23
|
+
--bs-gray-200: color-mix(in lab, var(--bs-white) 60%, #8189a8);
|
|
24
|
+
--bs-gray-300: color-mix(in lab, var(--bs-white) 40%, #8189a8);
|
|
25
|
+
--bs-gray-400: color-mix(in lab, var(--bs-white) 20%, #8189a8);
|
|
26
|
+
--bs-gray-500: #8189a8;
|
|
27
|
+
--bs-gray-600: color-mix(in lab, var(--bs-black) 16%, #8189a8);
|
|
28
|
+
--bs-gray-700: color-mix(in lab, var(--bs-black) 32%, #8189a8);
|
|
29
|
+
--bs-gray-800: color-mix(in lab, var(--bs-black) 48%, #8189a8);
|
|
30
|
+
--bs-gray-900: color-mix(in lab, var(--bs-black) 64%, #8189a8);
|
|
31
|
+
--bs-gray-950: color-mix(in lab, var(--bs-black) 76%, #8189a8);
|
|
32
|
+
--bs-gray-975: color-mix(in lab, var(--bs-black) 88%, #8189a8);
|
|
33
|
+
|
|
34
|
+
--bs-blue-025: color-mix(in lab, var(--bs-white) 94%, #7aa2f7);
|
|
35
|
+
--bs-blue-050: color-mix(in lab, var(--bs-white) 90%, #7aa2f7);
|
|
36
|
+
--bs-blue-100: color-mix(in lab, var(--bs-white) 80%, #7aa2f7);
|
|
37
|
+
--bs-blue-200: color-mix(in lab, var(--bs-white) 60%, #7aa2f7);
|
|
38
|
+
--bs-blue-300: color-mix(in lab, var(--bs-white) 40%, #7aa2f7);
|
|
39
|
+
--bs-blue-400: color-mix(in lab, var(--bs-white) 20%, #7aa2f7);
|
|
40
|
+
--bs-blue-500: #7aa2f7;
|
|
41
|
+
--bs-blue-600: color-mix(in lab, var(--bs-black) 16%, #7aa2f7);
|
|
42
|
+
--bs-blue-700: color-mix(in lab, var(--bs-black) 32%, #7aa2f7);
|
|
43
|
+
--bs-blue-800: color-mix(in lab, var(--bs-black) 48%, #7aa2f7);
|
|
44
|
+
--bs-blue-900: color-mix(in lab, var(--bs-black) 64%, #7aa2f7);
|
|
45
|
+
--bs-blue-950: color-mix(in lab, var(--bs-black) 76%, #7aa2f7);
|
|
46
|
+
--bs-blue-975: color-mix(in lab, var(--bs-black) 88%, #7aa2f7);
|
|
47
|
+
|
|
48
|
+
--bs-brown-025: color-mix(in lab, var(--bs-white) 94%, #ff9e64);
|
|
49
|
+
--bs-brown-050: color-mix(in lab, var(--bs-white) 90%, #ff9e64);
|
|
50
|
+
--bs-brown-100: color-mix(in lab, var(--bs-white) 80%, #ff9e64);
|
|
51
|
+
--bs-brown-200: color-mix(in lab, var(--bs-white) 60%, #ff9e64);
|
|
52
|
+
--bs-brown-300: color-mix(in lab, var(--bs-white) 40%, #ff9e64);
|
|
53
|
+
--bs-brown-400: color-mix(in lab, var(--bs-white) 20%, #ff9e64);
|
|
54
|
+
--bs-brown-500: #ff9e64;
|
|
55
|
+
--bs-brown-600: color-mix(in lab, var(--bs-black) 16%, #ff9e64);
|
|
56
|
+
--bs-brown-700: color-mix(in lab, var(--bs-black) 32%, #ff9e64);
|
|
57
|
+
--bs-brown-800: color-mix(in lab, var(--bs-black) 48%, #ff9e64);
|
|
58
|
+
--bs-brown-900: color-mix(in lab, var(--bs-black) 64%, #ff9e64);
|
|
59
|
+
--bs-brown-950: color-mix(in lab, var(--bs-black) 76%, #ff9e64);
|
|
60
|
+
--bs-brown-975: color-mix(in lab, var(--bs-black) 88%, #ff9e64);
|
|
61
|
+
|
|
62
|
+
--bs-cyan-025: color-mix(in lab, var(--bs-white) 94%, #7dcfff);
|
|
63
|
+
--bs-cyan-050: color-mix(in lab, var(--bs-white) 90%, #7dcfff);
|
|
64
|
+
--bs-cyan-100: color-mix(in lab, var(--bs-white) 80%, #7dcfff);
|
|
65
|
+
--bs-cyan-200: color-mix(in lab, var(--bs-white) 60%, #7dcfff);
|
|
66
|
+
--bs-cyan-300: color-mix(in lab, var(--bs-white) 40%, #7dcfff);
|
|
67
|
+
--bs-cyan-400: color-mix(in lab, var(--bs-white) 20%, #7dcfff);
|
|
68
|
+
--bs-cyan-500: #7dcfff;
|
|
69
|
+
--bs-cyan-600: color-mix(in lab, var(--bs-black) 16%, #7dcfff);
|
|
70
|
+
--bs-cyan-700: color-mix(in lab, var(--bs-black) 32%, #7dcfff);
|
|
71
|
+
--bs-cyan-800: color-mix(in lab, var(--bs-black) 48%, #7dcfff);
|
|
72
|
+
--bs-cyan-900: color-mix(in lab, var(--bs-black) 64%, #7dcfff);
|
|
73
|
+
--bs-cyan-950: color-mix(in lab, var(--bs-black) 76%, #7dcfff);
|
|
74
|
+
--bs-cyan-975: color-mix(in lab, var(--bs-black) 88%, #7dcfff);
|
|
75
|
+
|
|
76
|
+
--bs-green-025: color-mix(in lab, var(--bs-white) 94%, #9ece6a);
|
|
77
|
+
--bs-green-050: color-mix(in lab, var(--bs-white) 90%, #9ece6a);
|
|
78
|
+
--bs-green-100: color-mix(in lab, var(--bs-white) 80%, #9ece6a);
|
|
79
|
+
--bs-green-200: color-mix(in lab, var(--bs-white) 60%, #9ece6a);
|
|
80
|
+
--bs-green-300: color-mix(in lab, var(--bs-white) 40%, #9ece6a);
|
|
81
|
+
--bs-green-400: color-mix(in lab, var(--bs-white) 20%, #9ece6a);
|
|
82
|
+
--bs-green-500: #9ece6a;
|
|
83
|
+
--bs-green-600: color-mix(in lab, var(--bs-black) 16%, #9ece6a);
|
|
84
|
+
--bs-green-700: color-mix(in lab, var(--bs-black) 32%, #9ece6a);
|
|
85
|
+
--bs-green-800: color-mix(in lab, var(--bs-black) 48%, #9ece6a);
|
|
86
|
+
--bs-green-900: color-mix(in lab, var(--bs-black) 64%, #9ece6a);
|
|
87
|
+
--bs-green-950: color-mix(in lab, var(--bs-black) 76%, #9ece6a);
|
|
88
|
+
--bs-green-975: color-mix(in lab, var(--bs-black) 88%, #9ece6a);
|
|
89
|
+
|
|
90
|
+
--bs-orange-025: color-mix(in lab, var(--bs-white) 94%, #ff9e64);
|
|
91
|
+
--bs-orange-050: color-mix(in lab, var(--bs-white) 90%, #ff9e64);
|
|
92
|
+
--bs-orange-100: color-mix(in lab, var(--bs-white) 80%, #ff9e64);
|
|
93
|
+
--bs-orange-200: color-mix(in lab, var(--bs-white) 60%, #ff9e64);
|
|
94
|
+
--bs-orange-300: color-mix(in lab, var(--bs-white) 40%, #ff9e64);
|
|
95
|
+
--bs-orange-400: color-mix(in lab, var(--bs-white) 20%, #ff9e64);
|
|
96
|
+
--bs-orange-500: #ff9e64;
|
|
97
|
+
--bs-orange-600: color-mix(in lab, var(--bs-black) 16%, #ff9e64);
|
|
98
|
+
--bs-orange-700: color-mix(in lab, var(--bs-black) 32%, #ff9e64);
|
|
99
|
+
--bs-orange-800: color-mix(in lab, var(--bs-black) 48%, #ff9e64);
|
|
100
|
+
--bs-orange-900: color-mix(in lab, var(--bs-black) 64%, #ff9e64);
|
|
101
|
+
--bs-orange-950: color-mix(in lab, var(--bs-black) 76%, #ff9e64);
|
|
102
|
+
--bs-orange-975: color-mix(in lab, var(--bs-black) 88%, #ff9e64);
|
|
103
|
+
|
|
104
|
+
--bs-pink-025: color-mix(in lab, var(--bs-white) 94%, #bb9af7);
|
|
105
|
+
--bs-pink-050: color-mix(in lab, var(--bs-white) 90%, #bb9af7);
|
|
106
|
+
--bs-pink-100: color-mix(in lab, var(--bs-white) 80%, #bb9af7);
|
|
107
|
+
--bs-pink-200: color-mix(in lab, var(--bs-white) 60%, #bb9af7);
|
|
108
|
+
--bs-pink-300: color-mix(in lab, var(--bs-white) 40%, #bb9af7);
|
|
109
|
+
--bs-pink-400: color-mix(in lab, var(--bs-white) 20%, #bb9af7);
|
|
110
|
+
--bs-pink-500: #bb9af7;
|
|
111
|
+
--bs-pink-600: color-mix(in lab, var(--bs-black) 16%, #bb9af7);
|
|
112
|
+
--bs-pink-700: color-mix(in lab, var(--bs-black) 32%, #bb9af7);
|
|
113
|
+
--bs-pink-800: color-mix(in lab, var(--bs-black) 48%, #bb9af7);
|
|
114
|
+
--bs-pink-900: color-mix(in lab, var(--bs-black) 64%, #bb9af7);
|
|
115
|
+
--bs-pink-950: color-mix(in lab, var(--bs-black) 76%, #bb9af7);
|
|
116
|
+
--bs-pink-975: color-mix(in lab, var(--bs-black) 88%, #bb9af7);
|
|
117
|
+
|
|
118
|
+
--bs-purple-025: color-mix(in lab, var(--bs-white) 94%, #bb9af7);
|
|
119
|
+
--bs-purple-050: color-mix(in lab, var(--bs-white) 90%, #bb9af7);
|
|
120
|
+
--bs-purple-100: color-mix(in lab, var(--bs-white) 80%, #bb9af7);
|
|
121
|
+
--bs-purple-200: color-mix(in lab, var(--bs-white) 60%, #bb9af7);
|
|
122
|
+
--bs-purple-300: color-mix(in lab, var(--bs-white) 40%, #bb9af7);
|
|
123
|
+
--bs-purple-400: color-mix(in lab, var(--bs-white) 20%, #bb9af7);
|
|
124
|
+
--bs-purple-500: #bb9af7;
|
|
125
|
+
--bs-purple-600: color-mix(in lab, var(--bs-black) 16%, #bb9af7);
|
|
126
|
+
--bs-purple-700: color-mix(in lab, var(--bs-black) 32%, #bb9af7);
|
|
127
|
+
--bs-purple-800: color-mix(in lab, var(--bs-black) 48%, #bb9af7);
|
|
128
|
+
--bs-purple-900: color-mix(in lab, var(--bs-black) 64%, #bb9af7);
|
|
129
|
+
--bs-purple-950: color-mix(in lab, var(--bs-black) 76%, #bb9af7);
|
|
130
|
+
--bs-purple-975: color-mix(in lab, var(--bs-black) 88%, #bb9af7);
|
|
131
|
+
|
|
132
|
+
--bs-red-025: color-mix(in lab, var(--bs-white) 94%, #f7768e);
|
|
133
|
+
--bs-red-050: color-mix(in lab, var(--bs-white) 90%, #f7768e);
|
|
134
|
+
--bs-red-100: color-mix(in lab, var(--bs-white) 80%, #f7768e);
|
|
135
|
+
--bs-red-200: color-mix(in lab, var(--bs-white) 60%, #f7768e);
|
|
136
|
+
--bs-red-300: color-mix(in lab, var(--bs-white) 40%, #f7768e);
|
|
137
|
+
--bs-red-400: color-mix(in lab, var(--bs-white) 20%, #f7768e);
|
|
138
|
+
--bs-red-500: #f7768e;
|
|
139
|
+
--bs-red-600: color-mix(in lab, var(--bs-black) 16%, #f7768e);
|
|
140
|
+
--bs-red-700: color-mix(in lab, var(--bs-black) 32%, #f7768e);
|
|
141
|
+
--bs-red-800: color-mix(in lab, var(--bs-black) 48%, #f7768e);
|
|
142
|
+
--bs-red-900: color-mix(in lab, var(--bs-black) 64%, #f7768e);
|
|
143
|
+
--bs-red-950: color-mix(in lab, var(--bs-black) 76%, #f7768e);
|
|
144
|
+
--bs-red-975: color-mix(in lab, var(--bs-black) 88%, #f7768e);
|
|
145
|
+
|
|
146
|
+
--bs-yellow-025: color-mix(in lab, var(--bs-white) 94%, #e0af68);
|
|
147
|
+
--bs-yellow-050: color-mix(in lab, var(--bs-white) 90%, #e0af68);
|
|
148
|
+
--bs-yellow-100: color-mix(in lab, var(--bs-white) 80%, #e0af68);
|
|
149
|
+
--bs-yellow-200: color-mix(in lab, var(--bs-white) 60%, #e0af68);
|
|
150
|
+
--bs-yellow-300: color-mix(in lab, var(--bs-white) 40%, #e0af68);
|
|
151
|
+
--bs-yellow-400: color-mix(in lab, var(--bs-white) 20%, #e0af68);
|
|
152
|
+
--bs-yellow-500: #e0af68;
|
|
153
|
+
--bs-yellow-600: color-mix(in lab, var(--bs-black) 16%, #e0af68);
|
|
154
|
+
--bs-yellow-700: color-mix(in lab, var(--bs-black) 32%, #e0af68);
|
|
155
|
+
--bs-yellow-800: color-mix(in lab, var(--bs-black) 48%, #e0af68);
|
|
156
|
+
--bs-yellow-900: color-mix(in lab, var(--bs-black) 64%, #e0af68);
|
|
157
|
+
--bs-yellow-950: color-mix(in lab, var(--bs-black) 76%, #e0af68);
|
|
158
|
+
--bs-yellow-975: color-mix(in lab, var(--bs-black) 88%, #e0af68);
|
|
159
|
+
|
|
160
|
+
/* Text, stated rather than left to the ramp. Bootstrap pairs a low step as
|
|
161
|
+
a light surface with that same step as dark-mode text, which a palette
|
|
162
|
+
built for its own contrast does not agree with. */
|
|
163
|
+
--bs-fg-1: light-dark(#1a1b26, #c0caf5);
|
|
164
|
+
--bs-fg-body: light-dark(#343b58, #a9b1d6);
|
|
165
|
+
--bs-fg-2: light-dark(#565f89, #8b93b5);
|
|
166
|
+
|
|
167
|
+
/* The label a solid fill carries, for the four families Bootstrap has
|
|
168
|
+
spent on a meaning and this palette has repainted. Upstream's own shape:
|
|
169
|
+
it gives warning and info a dark label for the same reason. */
|
|
170
|
+
--bs-danger-contrast: var(--bs-gray-975);
|
|
171
|
+
--bs-success-contrast: var(--bs-gray-975);
|
|
172
|
+
--bs-warning-contrast: var(--bs-gray-975);
|
|
173
|
+
--bs-info-contrast: var(--bs-gray-975);
|
|
174
|
+
|
|
175
|
+
/* The accent this palette leads with, as the primary color: the same nine
|
|
176
|
+
`_color.html.erb` writes, from blue and the label that reads on it. Here
|
|
177
|
+
rather than only in the page because a reader may swap this file for
|
|
178
|
+
another one, and the primary has to travel with it. A host naming its
|
|
179
|
+
own color still wins, its block coming after this file. */
|
|
180
|
+
--bs-primary-base: var(--bs-blue-500);
|
|
181
|
+
--bs-primary-fg: light-dark(var(--bs-blue-600), var(--bs-blue-400));
|
|
182
|
+
--bs-primary-fg-emphasis: light-dark(var(--bs-blue-800), var(--bs-blue-200));
|
|
183
|
+
--bs-primary-bg: var(--bs-blue-500);
|
|
184
|
+
--bs-primary-bg-subtle: light-dark(var(--bs-blue-100), var(--bs-blue-900));
|
|
185
|
+
--bs-primary-bg-muted: light-dark(var(--bs-blue-200), var(--bs-blue-800));
|
|
186
|
+
--bs-primary-border: light-dark(var(--bs-blue-300), var(--bs-blue-600));
|
|
187
|
+
--bs-primary-focus-ring: light-dark(color-mix(in oklch, var(--bs-blue-500) 50%, var(--bs-bg-body)), color-mix(in oklch, var(--bs-blue-500) 75%, var(--bs-bg-body)));
|
|
188
|
+
--bs-primary-contrast: var(--bs-gray-975);
|
|
189
|
+
}
|
data/build.mjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Builds the stylesheet and the script into public/bh/, under the prefix the engine serves them
|
|
2
|
+
// at, which is also what the gem ships. Every URL inside is relative to the file holding it,
|
|
3
|
+
// so one build answers from the gem and from a CDN carrying the package alike.
|
|
4
|
+
import { build } from 'esbuild'
|
|
5
|
+
import { cpSync, mkdirSync } from 'node:fs'
|
|
6
|
+
|
|
7
|
+
await build({
|
|
8
|
+
entryPoints: ['app/javascript/bh.js', 'app/stylesheets/bh.css'],
|
|
9
|
+
bundle: true,
|
|
10
|
+
minify: true,
|
|
11
|
+
format: 'esm',
|
|
12
|
+
outdir: 'public/bh',
|
|
13
|
+
entryNames: '[ext]/[name]',
|
|
14
|
+
alias: { bootstrap: './vendor/bootstrap.bundle.min.js' },
|
|
15
|
+
logLevel: 'info',
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
// The nine palettes are not bundled: a page links one at a time and swaps it for another,
|
|
19
|
+
// which is the whole point of them, so they are copied beside the stylesheet as they are.
|
|
20
|
+
mkdirSync('public/bh/theme', { recursive: true })
|
|
21
|
+
cpSync('app/stylesheets/theme', 'public/bh/theme', { recursive: true })
|
data/lib/bh/engine.rb
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
# rails/engine alone raises NoMethodError: railtie.rb calls delegate_missing_to too early.
|
|
2
|
+
require 'rails'
|
|
2
3
|
|
|
3
4
|
module Bh
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
# Hooks the gem into a host app: serves the built stylesheet and script, and the helpers.
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
# Where the built files answer from: one prefix of the gem's own, so a host already
|
|
8
|
+
# serving `/css` from somewhere else keeps it. The slash is kept, since `Rack::Static`
|
|
9
|
+
# matches on `start_with?` and `/bh` would swallow a host's own `/bhutan`.
|
|
10
|
+
PREFIX = '/bh/'.freeze
|
|
11
|
+
|
|
12
|
+
# Neither URL carries a version, so both are asked for again on every full load and
|
|
13
|
+
# answered `304 Not Modified` while the file they name still stands.
|
|
14
|
+
HEADERS = [[:all, { 'cache-control' => 'no-cache' }]].freeze
|
|
8
15
|
|
|
16
|
+
# Before `Rails::Rack::Logger`, so fetching the stylesheet writes no `Started GET` line,
|
|
17
|
+
# and cascading, so a host route under the prefix still answers.
|
|
9
18
|
initializer 'bh.assets' do |app|
|
|
10
|
-
app.
|
|
19
|
+
app.middleware.insert_before Rails::Rack::Logger, Rack::Static,
|
|
20
|
+
urls: [PREFIX], root: Engine.root.join('public').to_s,
|
|
21
|
+
header_rules: HEADERS, cascade: true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
initializer 'bh.helpers' do
|
|
25
|
+
ActiveSupport.on_load(:action_view) { include Bh::Helpers }
|
|
11
26
|
end
|
|
12
27
|
end
|
|
13
28
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module Bh
|
|
4
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
5
|
+
# The menu the bundle draws as a combobox: Bootstrap's toggle and a searchable menu built
|
|
6
|
+
# from a select it then hides, which stays the one thing the form submits.
|
|
7
|
+
module Comboboxes
|
|
8
|
+
# The words the menu is read by, which belong to the gem rather than to a page.
|
|
9
|
+
WORDS = %i[all clear more no_results search].freeze
|
|
10
|
+
|
|
11
|
+
# `method` as a combobox over `choices` -- the select `form.select` would draw, carrying
|
|
12
|
+
# what the bundle needs to draw it as one instead. Every argument is that select's, and
|
|
13
|
+
# its own `:prompt` is what the toggle says before anything is picked. The words it is
|
|
14
|
+
# searched, cleared and emptied by are the gem's, in the reader's own language, and
|
|
15
|
+
# `data` given in `html_options` is kept over any of them.
|
|
16
|
+
def combobox(method, choices = nil, options = {}, html_options = {}, &)
|
|
17
|
+
data = { controller: 'combobox', combobox_placeholder_value: options[:prompt],
|
|
18
|
+
**bh_combobox_words, **html_options.fetch(:data, {}), }
|
|
19
|
+
|
|
20
|
+
select method, choices, options, html_options.merge(data: data), &
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# `all` and `more` are Stimulus values the menu reads; the rest are plain attributes.
|
|
26
|
+
# `more` is a template the bundle fills, so it is asked for with its own placeholders as
|
|
27
|
+
# their values -- I18n would otherwise raise on the two it cannot fill.
|
|
28
|
+
def bh_combobox_words
|
|
29
|
+
WORDS.to_h do |word|
|
|
30
|
+
# rubocop:disable-next Style/FormatStringToken -- the bundle fills these, not Ruby
|
|
31
|
+
said = @template.t "bh.#{word}", first: '%{first}', count: '%{count}'
|
|
32
|
+
|
|
33
|
+
[%i[all more].include?(word) ? :"combobox_#{word}_value" : word, said]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module Bh
|
|
4
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
5
|
+
# Every other kind of field, at the one size this builder draws them: a page says which kind
|
|
6
|
+
# it wants and nothing about how it looks. Rails hands an undressed control to whatever it
|
|
7
|
+
# has no method for here, which is how a Bootstrap class ends up written in a view.
|
|
8
|
+
module Controls
|
|
9
|
+
# What a menu wears: the control's size, so a menu and a box beside it line up.
|
|
10
|
+
MENU = 'form-select form-select-lg'
|
|
11
|
+
|
|
12
|
+
# What a box or a circle that is ticked wears.
|
|
13
|
+
CHECK = 'form-check-input'
|
|
14
|
+
|
|
15
|
+
# An email address.
|
|
16
|
+
def email_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
17
|
+
|
|
18
|
+
# A number, which brings the keyboard for one.
|
|
19
|
+
def number_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
20
|
+
|
|
21
|
+
# A password, which no name of a column earns on its own.
|
|
22
|
+
def password_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
23
|
+
|
|
24
|
+
# A term to search by.
|
|
25
|
+
def search_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
26
|
+
|
|
27
|
+
# A web address.
|
|
28
|
+
def url_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
29
|
+
|
|
30
|
+
# A day.
|
|
31
|
+
def date_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
32
|
+
|
|
33
|
+
# A time of day.
|
|
34
|
+
def time_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
35
|
+
|
|
36
|
+
# A day and a time together.
|
|
37
|
+
def datetime_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
38
|
+
|
|
39
|
+
# More than a line of words.
|
|
40
|
+
def text_area(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
41
|
+
|
|
42
|
+
# A menu of what a column may be.
|
|
43
|
+
def select(method, choices = nil, options = {}, html_options = {}, &)
|
|
44
|
+
super(method, choices, options, with_classes(html_options, MENU), &)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# One of several, ticked.
|
|
48
|
+
def check_box(method, options = {}, checked = '1', unchecked = '0')
|
|
49
|
+
super(method, with_classes(options, CHECK), checked, unchecked)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# One of several, and only one.
|
|
53
|
+
def radio_button(method, value, options = {})
|
|
54
|
+
super(method, value, with_classes(options, CHECK))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# A box and the words beside it, which is the one place words sit after a control rather
|
|
58
|
+
# than over it -- so they are not the label a field wears, and are written here instead.
|
|
59
|
+
def check(method, text, options = {})
|
|
60
|
+
words = @template.label_tag field_id(method), text, class: 'form-check-label'
|
|
61
|
+
inside = @template.safe_join [check_box(method, options), words]
|
|
62
|
+
|
|
63
|
+
@template.tag.div inside, class: 'form-check'
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module Bh
|
|
4
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
5
|
+
# The field Rails has none of: the six slots a code is typed into.
|
|
6
|
+
module Pins
|
|
7
|
+
# What the one real PIN field carries: digits only, six of them, offered by the phone from
|
|
8
|
+
# the text that brought them, and drawn as slots by Bootstrap and the `otp` controller.
|
|
9
|
+
PIN = {
|
|
10
|
+
class: 'otp-input', inputmode: :numeric, pattern: '[0-9]{6}', minlength: 6, maxlength: 6,
|
|
11
|
+
autocomplete: 'one-time-code',
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
# `method` as Bootstrap's OTP input: one real field rendered as six slots, the slots
|
|
15
|
+
# reddened where the record refused the code. Every option is the field's. The field is
|
|
16
|
+
# drawn by the view rather than this builder on purpose, so it is never dressed as a
|
|
17
|
+
# `form-control`: a refused one would wear a red box of its own around slots that say so.
|
|
18
|
+
def pin_field(method, **options)
|
|
19
|
+
invalid = @object.respond_to?(:errors) && @object.errors.include?(method)
|
|
20
|
+
classes = @template.class_names 'otp otp-lg', 'is-invalid': invalid
|
|
21
|
+
|
|
22
|
+
field = with_classes PIN.merge(options), PIN[:class]
|
|
23
|
+
|
|
24
|
+
@template.tag.div class: classes, data: { controller: 'otp', bs_otp: true } do
|
|
25
|
+
@template.text_field @object_name, method, **field, object: @object
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|