bullet_train 1.6.30 → 1.6.31
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/app/mailers/concerns/mailers/base.rb +1 -1
- data/docs/themes/on-jumpstart-pro-projects.md +488 -0
- data/docs/themes/on-other-rails-projects.md +301 -0
- data/docs/themes.md +5 -0
- data/lib/bullet_train/version.rb +1 -1
- data/lib/tasks/bullet_train_tasks.rake +0 -27
- metadata +4 -6
- data/app/helpers/account/dates_helper.rb +0 -70
- data/app/helpers/account/forms_helper.rb +0 -65
- data/app/helpers/attributes_helper.rb +0 -17
- data/app/helpers/images_helper.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f095a907ffb4c58ff8e8f719eea4b1e4f4b800cf0784e54578ce0373485b2cd
|
4
|
+
data.tar.gz: 14d1cc067198dce1abc19bbc3edbf6c79007a9f73b073e97ed9d6ad3ccab5839
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57f1ed1e18979735a4801a02fe386e252c7b10c52d5619ab2c065b0a56aa0510c0c2bbfc81a43200ad4f88f644705ec9478cde3d09ef898a5ea60c42f85611a4
|
7
|
+
data.tar.gz: 9792cf9800fcbfe7c72a80ccf07723447ad2444fd084097632c31dd5292c033c71d20aabc441419ac8e700380d8c774cf1f5b266e591355ff49ed1f0c1380ee1
|
@@ -0,0 +1,488 @@
|
|
1
|
+
# Installing Bullet-Train Themes on Jumpstart PRO Projects
|
2
|
+
|
3
|
+
Bullet Train themes can be installed on Jumpstart PRO projects, giving you native `erb` partials and Hotwire-powered UI components.
|
4
|
+
|
5
|
+
Like Jumpstart PRO, Bullet Train themes are built using `tailwindcss` and use `esbuild` and `postcss` for JavaScript and style sheets.
|
6
|
+
|
7
|
+
To get a quick sense of the UI components, we encourage you to spin up a Bullet Train project and navigate through the screens to create a "Creative Concept" and "Tangible Thing" resources.
|
8
|
+
|
9
|
+
In addition to providing a nice set of UI components, you'll get access to [`nice_partials`](https://github.com/bullet-train-co/nice_partials), Bullet-Train's own lightweight answer for creating `erb` partials with ad-hoc named content areas, which we think is just the right amount of magic for making `erb`-based components.
|
10
|
+
|
11
|
+
Note: we also have [instructions for installing themes on other Rails projects](on-other-rails-projects.md).
|
12
|
+
|
13
|
+
**Contents:**
|
14
|
+
|
15
|
+
1. Installation Instructions
|
16
|
+
2. Optional Configurations for switching colors, theme gems
|
17
|
+
3. Using Locales for fields on new models
|
18
|
+
4. Partials that require special instructions, exclusions
|
19
|
+
5. Modifying ejected partials
|
20
|
+
|
21
|
+
## 1. Installation Instructions
|
22
|
+
|
23
|
+
### Add the theme gem
|
24
|
+
|
25
|
+
These instructions assume you're installing the `Light` theme bundled with Bullet Train.
|
26
|
+
|
27
|
+
```
|
28
|
+
bundle add bullet_train-themes-light
|
29
|
+
```
|
30
|
+
|
31
|
+
Or add the following to your `Gemfile`:
|
32
|
+
|
33
|
+
```
|
34
|
+
gem "bullet_train-themes-light"
|
35
|
+
```
|
36
|
+
|
37
|
+
And then run:
|
38
|
+
|
39
|
+
```
|
40
|
+
bundle install
|
41
|
+
```
|
42
|
+
|
43
|
+
### Add `npm` packages
|
44
|
+
|
45
|
+
The `Light` theme requires the following npm packages to be installed
|
46
|
+
|
47
|
+
```
|
48
|
+
yarn add @bullet-train/bullet-train @bullet-train/fields autoprefixer @rails/actiontext postcss-extend-rule
|
49
|
+
```
|
50
|
+
|
51
|
+
Update your `app/javascript/controllers/index.js` with the following lines:
|
52
|
+
|
53
|
+
```js
|
54
|
+
import { controllerDefinitions as bulletTrainControllers } from "@bullet-train/bullet-train"
|
55
|
+
import { controllerDefinitions as bulletTrainFieldControllers } from "@bullet-train/fields"
|
56
|
+
|
57
|
+
application.load(bulletTrainControllers)
|
58
|
+
application.load(bulletTrainFieldControllers)
|
59
|
+
```
|
60
|
+
|
61
|
+
### Add `bin/theme` and `bin/link` bin stubs
|
62
|
+
|
63
|
+
```
|
64
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/bin/theme" -o bin/theme
|
65
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/bin/link" -o bin/link
|
66
|
+
chmod +x bin/theme bin/link
|
67
|
+
```
|
68
|
+
|
69
|
+
### Update `esbuild.config.mjs`
|
70
|
+
|
71
|
+
Replace it with these contents.
|
72
|
+
|
73
|
+
```js
|
74
|
+
#!/usr/bin/env node
|
75
|
+
|
76
|
+
// Esbuild is configured with 3 modes:
|
77
|
+
//
|
78
|
+
// `yarn build` - Build JavaScript and exit
|
79
|
+
// `yarn build --watch` - Rebuild JavaScript on change
|
80
|
+
// `yarn build --reload` - Reloads page when views, JavaScript, or stylesheets change. Requires a PORT to listen on. Defaults to 3200 but can be specified with PORT env var
|
81
|
+
//
|
82
|
+
// Minify is enabled when "RAILS_ENV=production"
|
83
|
+
// Sourcemaps are enabled in non-production environments
|
84
|
+
|
85
|
+
import * as esbuild from "esbuild"
|
86
|
+
import path from "path"
|
87
|
+
import { execSync } from "child_process"
|
88
|
+
import rails from "esbuild-rails"
|
89
|
+
import chokidar from "chokidar"
|
90
|
+
import http from "http"
|
91
|
+
import { setTimeout } from "timers/promises"
|
92
|
+
|
93
|
+
let themeFile = ""
|
94
|
+
if (process.env.THEME) {
|
95
|
+
themeFile = execSync(`bundle exec bin/theme javascript ${process.env.THEME}`).toString().trim()
|
96
|
+
}
|
97
|
+
|
98
|
+
const themeEntrypoints = {}
|
99
|
+
if (process.env.THEME) {
|
100
|
+
themeEntrypoints[`application.${process.env.THEME}`] = themeFile
|
101
|
+
}
|
102
|
+
|
103
|
+
const clients = []
|
104
|
+
const entryPoints = {
|
105
|
+
"application": path.join(process.cwd(), "app/javascript/application.js"),
|
106
|
+
"administrate": path.join(process.cwd(), "app/javascript/administrate.js"),
|
107
|
+
...themeEntrypoints,
|
108
|
+
}
|
109
|
+
const watchDirectories = [
|
110
|
+
"./app/javascript/**/*.js",
|
111
|
+
"./app/views/**/*.html.erb",
|
112
|
+
"./app/assets/builds/**/*.css", // Wait for cssbundling changes
|
113
|
+
"./config/locales/**/*.yml",
|
114
|
+
]
|
115
|
+
const config = {
|
116
|
+
absWorkingDir: path.join(process.cwd(), "app/javascript"),
|
117
|
+
bundle: true,
|
118
|
+
entryPoints: entryPoints,
|
119
|
+
minify: process.env.RAILS_ENV == "production",
|
120
|
+
outdir: path.join(process.cwd(), "app/assets/builds"),
|
121
|
+
plugins: [rails()],
|
122
|
+
sourcemap: process.env.RAILS_ENV != "production",
|
123
|
+
define: {
|
124
|
+
global: "window"
|
125
|
+
},
|
126
|
+
loader: {
|
127
|
+
".png": "file",
|
128
|
+
".jpg": "file",
|
129
|
+
".svg": "file",
|
130
|
+
".woff": "file",
|
131
|
+
".woff2": "file",
|
132
|
+
".ttf": "file",
|
133
|
+
".eot": "file",
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
async function buildAndReload() {
|
138
|
+
// Foreman & Overmind assign a separate PORT for each process
|
139
|
+
const port = parseInt(process.env.PORT || 3200)
|
140
|
+
console.log(`Esbuild is listening on port ${port}`)
|
141
|
+
const context = await esbuild.context({
|
142
|
+
...config,
|
143
|
+
banner: {
|
144
|
+
js: ` (() => new EventSource("http://localhost:${port}").onmessage = () => location.reload())();`,
|
145
|
+
}
|
146
|
+
})
|
147
|
+
|
148
|
+
// Reload uses an HTTP server as an even stream to reload the browser
|
149
|
+
http
|
150
|
+
.createServer((req, res) => {
|
151
|
+
return clients.push(
|
152
|
+
res.writeHead(200, {
|
153
|
+
"Content-Type": "text/event-stream",
|
154
|
+
"Cache-Control": "no-cache",
|
155
|
+
"Access-Control-Allow-Origin": "*",
|
156
|
+
Connection: "keep-alive",
|
157
|
+
})
|
158
|
+
)
|
159
|
+
})
|
160
|
+
.listen(port)
|
161
|
+
|
162
|
+
await context.rebuild()
|
163
|
+
console.log("[reload] initial build succeeded")
|
164
|
+
|
165
|
+
let ready = false
|
166
|
+
chokidar
|
167
|
+
.watch(watchDirectories)
|
168
|
+
.on("ready", () => {
|
169
|
+
console.log("[reload] ready")
|
170
|
+
ready = true
|
171
|
+
})
|
172
|
+
.on("all", async (event, path) => {
|
173
|
+
if (ready === false) return
|
174
|
+
|
175
|
+
if (path.includes("javascript")) {
|
176
|
+
try {
|
177
|
+
await setTimeout(20)
|
178
|
+
await context.rebuild()
|
179
|
+
console.log("[reload] build succeeded")
|
180
|
+
} catch (error) {
|
181
|
+
console.error("[reload] build failed", error)
|
182
|
+
}
|
183
|
+
}
|
184
|
+
clients.forEach((res) => res.write("data: update\n\n"))
|
185
|
+
clients.length = 0
|
186
|
+
})
|
187
|
+
}
|
188
|
+
|
189
|
+
if (process.argv.includes("--reload")) {
|
190
|
+
buildAndReload()
|
191
|
+
} else if (process.argv.includes("--watch")) {
|
192
|
+
let context = await esbuild.context({...config, logLevel: 'info'})
|
193
|
+
context.watch()
|
194
|
+
} else {
|
195
|
+
esbuild.build(config)
|
196
|
+
}
|
197
|
+
```
|
198
|
+
|
199
|
+
### Update `tailwind.config.js`
|
200
|
+
|
201
|
+
Replace with these contents, which merge the Bullet Train-specific tailwind configs with those of Jumpstart PRO.
|
202
|
+
|
203
|
+
_Note: After this step, you might get an error on build about a missing `process.env.THEME`. Follow with the next step to fix this error._
|
204
|
+
|
205
|
+
```js
|
206
|
+
const path = require('path');
|
207
|
+
const { execSync } = require("child_process");
|
208
|
+
const glob = require('glob').sync
|
209
|
+
|
210
|
+
if (!process.env.THEME) {
|
211
|
+
throw "tailwind.config.js: missing process.env.THEME"
|
212
|
+
process.exit(1)
|
213
|
+
}
|
214
|
+
|
215
|
+
const themeConfigFile = execSync(`bundle exec bin/theme tailwind-config ${process.env.THEME}`).toString().trim()
|
216
|
+
let themeConfig = require(themeConfigFile)
|
217
|
+
|
218
|
+
const colors = require('tailwindcss/colors')
|
219
|
+
const defaultTheme = require('tailwindcss/defaultTheme')
|
220
|
+
|
221
|
+
themeConfig.darkMode = 'class'
|
222
|
+
|
223
|
+
themeConfig.plugins.push(require('@tailwindcss/aspect-ratio'))
|
224
|
+
|
225
|
+
themeConfig.content = [
|
226
|
+
...new Set([
|
227
|
+
...themeConfig.content,
|
228
|
+
'./app/components/**/*.rb',
|
229
|
+
'./app/helpers/**/*.rb',
|
230
|
+
'./app/javascript/**/*.js',
|
231
|
+
'./app/views/**/*.erb',
|
232
|
+
'./app/views/**/*.haml',
|
233
|
+
'./app/views/**/*.slim',
|
234
|
+
'./lib/jumpstart/app/views/**/*.erb',
|
235
|
+
'./lib/jumpstart/app/helpers/**/*.rb'
|
236
|
+
])
|
237
|
+
]
|
238
|
+
|
239
|
+
themeConfig.theme.extend.colors = {
|
240
|
+
...themeConfig.theme.extend.colors,
|
241
|
+
primary: colors.blue,
|
242
|
+
secondary: colors.emerald,
|
243
|
+
tertiary: colors.gray,
|
244
|
+
danger: colors.red,
|
245
|
+
gray: colors.neutral,
|
246
|
+
"code-400": "#fefcf9",
|
247
|
+
"code-600": "#3c455b",
|
248
|
+
}
|
249
|
+
|
250
|
+
themeConfig.theme.extend.fontFamily = {
|
251
|
+
...themeConfig.theme.extend.fontFamily,
|
252
|
+
sans: ['Inter', ...defaultTheme.fontFamily.sans],
|
253
|
+
}
|
254
|
+
|
255
|
+
module.exports = themeConfig
|
256
|
+
```
|
257
|
+
|
258
|
+
### Update `build:css` in `package.json`
|
259
|
+
|
260
|
+
In `package.json`, replace the `build` and `build:css` entries under `scripts` with:
|
261
|
+
|
262
|
+
```json
|
263
|
+
"build": "THEME=\"light\" node esbuild.config.mjs",
|
264
|
+
"build:css": "bin/link; THEME=\"light\" tailwindcss --postcss --minify -c ./tailwind.config.js -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.tailwind.css",
|
265
|
+
```
|
266
|
+
|
267
|
+
### Add `stylesheet_link_tag` to `<head>`
|
268
|
+
|
269
|
+
Make sure you have the following three lines in your `<head>`, which should be defined in `app/views/layouts/application.html.erb`:
|
270
|
+
|
271
|
+
```erb
|
272
|
+
<%= stylesheet_link_tag "application", media: "all", "data-turbo-track": "reload" %>
|
273
|
+
<%= stylesheet_link_tag "application.tailwind", media: "all", "data-turbo-track": "reload" %>
|
274
|
+
<%= javascript_include_tag 'application.light', 'data-turbo-track': 'reload' %>
|
275
|
+
```
|
276
|
+
|
277
|
+
### Update `postcss.config.js`
|
278
|
+
|
279
|
+
Replace with these contents:
|
280
|
+
|
281
|
+
```js
|
282
|
+
const { execSync } = require("child_process");
|
283
|
+
|
284
|
+
const postcssImportConfigFile = execSync(`bundle exec bin/theme postcss-import-config ${process.env.THEME}`).toString().trim()
|
285
|
+
const postcssImportConfig = require(postcssImportConfigFile)
|
286
|
+
|
287
|
+
module.exports = {
|
288
|
+
plugins: [
|
289
|
+
require('postcss-import')(postcssImportConfig),
|
290
|
+
require('postcss-extend-rule'),
|
291
|
+
require('tailwindcss/nesting'),
|
292
|
+
require('tailwindcss'),
|
293
|
+
require('autoprefixer')
|
294
|
+
]
|
295
|
+
}
|
296
|
+
```
|
297
|
+
|
298
|
+
### Import the Theme Style Sheet
|
299
|
+
|
300
|
+
To your `application.tailwind.css` file, add the following line:
|
301
|
+
|
302
|
+
```css
|
303
|
+
@import "$ThemeStylesheetsDir/application.css";
|
304
|
+
```
|
305
|
+
|
306
|
+
### Add Themify Icons, jQuery (for now) and trix editor support
|
307
|
+
|
308
|
+
Note: jQuery is needed for some of our components, but defining `window.$` won't be required soon. See PR https://github.com/bullet-train-co/bullet_train-core/pull/765
|
309
|
+
|
310
|
+
```
|
311
|
+
yarn add @icon/themify-icons jquery
|
312
|
+
```
|
313
|
+
|
314
|
+
To your `application.js`, add the following line:
|
315
|
+
|
316
|
+
```js
|
317
|
+
import jquery from "jquery"
|
318
|
+
window.jQuery = jquery
|
319
|
+
window.$ = jquery
|
320
|
+
|
321
|
+
require("@icon/themify-icons/themify-icons.css")
|
322
|
+
|
323
|
+
import { trixEditor } from "@bullet-train/fields"
|
324
|
+
trixEditor()
|
325
|
+
```
|
326
|
+
|
327
|
+
### Add Locale Strings
|
328
|
+
|
329
|
+
Add these to your `config/locales/en.yml` under `en:`
|
330
|
+
|
331
|
+
```yml
|
332
|
+
date:
|
333
|
+
formats:
|
334
|
+
date_field: "%m/%d/%Y"
|
335
|
+
date_and_time_field: "%m/%d/%Y %l:%M %p"
|
336
|
+
date_controller: "MM/DD/YYYY"
|
337
|
+
time:
|
338
|
+
am: AM
|
339
|
+
pm: PM
|
340
|
+
formats:
|
341
|
+
date_field: "%m/%d/%Y"
|
342
|
+
date_and_time_field: "%m/%d/%Y %l:%M %p"
|
343
|
+
date_controller: "MM/DD/YYYY h:mm A"
|
344
|
+
daterangepicker:
|
345
|
+
firstDay: 1
|
346
|
+
separator: " - "
|
347
|
+
applyLabel: "Apply"
|
348
|
+
cancelLabel: "Cancel"
|
349
|
+
fromLabel: "From"
|
350
|
+
toLabel: "To"
|
351
|
+
customRangeLabel: "Custom"
|
352
|
+
weekLabel: "W"
|
353
|
+
daysOfWeek:
|
354
|
+
- "Su"
|
355
|
+
- "Mo"
|
356
|
+
- "Tu"
|
357
|
+
- "We"
|
358
|
+
- "Th"
|
359
|
+
- "Fr"
|
360
|
+
- "Sa"
|
361
|
+
monthNames:
|
362
|
+
- "January"
|
363
|
+
- "February"
|
364
|
+
- "March"
|
365
|
+
- "April"
|
366
|
+
- "May"
|
367
|
+
- "June"
|
368
|
+
- "July"
|
369
|
+
- "August"
|
370
|
+
- "September"
|
371
|
+
- "October"
|
372
|
+
- "November"
|
373
|
+
- "December"
|
374
|
+
date_range_controller:
|
375
|
+
today: Today
|
376
|
+
yesterday: yesterday
|
377
|
+
last7Days: Last 7 Days
|
378
|
+
last30Days: Last 30 Days
|
379
|
+
thisMonth: This Month
|
380
|
+
lastMonth: Last Month
|
381
|
+
global:
|
382
|
+
buttons:
|
383
|
+
other: Other
|
384
|
+
cancel: Cancel
|
385
|
+
bulk_select:
|
386
|
+
all: All
|
387
|
+
```
|
388
|
+
|
389
|
+
### Disable `display: block` on `label` elements
|
390
|
+
|
391
|
+
In `app/assets/stylesheets/components/forms.css`, find the line under `label {`:
|
392
|
+
|
393
|
+
```css
|
394
|
+
@apply block text-sm font-medium leading-5 text-gray-700 mb-1;
|
395
|
+
```
|
396
|
+
|
397
|
+
And remove the `block` token:
|
398
|
+
|
399
|
+
```css
|
400
|
+
@apply text-sm font-medium leading-5 text-gray-700 mb-1;
|
401
|
+
```
|
402
|
+
|
403
|
+
## 2. Optional Configurations for switching colors, theme gems
|
404
|
+
|
405
|
+
### For Setting the Active Color
|
406
|
+
|
407
|
+
```
|
408
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/initializers/theme.rb" -o initializers/theme.rb
|
409
|
+
```
|
410
|
+
|
411
|
+
Add the following classes to your `html` tag for your layout:
|
412
|
+
|
413
|
+
```erb
|
414
|
+
<html class="theme-<%= BulletTrain::Themes::Light.color %> <%= "theme-secondary-#{BulletTrain::Themes::Light.secondary_color}" if BulletTrain::Themes::Light.secondary_color %>"
|
415
|
+
```
|
416
|
+
|
417
|
+
### For Switching Between Installed Themes
|
418
|
+
|
419
|
+
If you'd like to create your own theme but would still like to build on top of `:light`, you'll need to have both gems installed and you'll be able to switch the current theme this way.
|
420
|
+
|
421
|
+
Define `current_theme` in `app/helpers/application_helper.rb`
|
422
|
+
|
423
|
+
```
|
424
|
+
module ApplicationHelper
|
425
|
+
def current_theme
|
426
|
+
:light
|
427
|
+
end
|
428
|
+
end
|
429
|
+
```
|
430
|
+
|
431
|
+
To change to use a different theme:
|
432
|
+
|
433
|
+
1. Change the value returned by `current_theme` to the new theme name
|
434
|
+
2. Change the name of the `THEME` env var defined in `build` and `build:css` in `package.json`
|
435
|
+
3. Change the name of the theme in the `javascript_include_tag` in the `<head>`.
|
436
|
+
|
437
|
+
## 3. Using Locales for fields on new models
|
438
|
+
|
439
|
+
The theme's field partials work best with locale strings that are defined for the model you're creating.
|
440
|
+
|
441
|
+
Example: you've created a Project model. Here we'll create a `projects.en.yml`
|
442
|
+
|
443
|
+
1. Run `curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train-core/main/bullet_train-super_scaffolding/config/locales/en/scaffolding/completely_concrete/tangible_things.en.yml" -o config/locales/projects.en.yml`
|
444
|
+
2. Search and replace `projects.en.yml` for `scaffolding/completely_concrete/tangible_things`, `Tangible Things`, `Tangible Thing`, `tangible_things` and `tangible_thing`. Replace with `projects`, `Projects`, `Project`, `projects` and `project` respectively.
|
445
|
+
3. Remove strings you won't be using. In particular, look for comments with "skip" or "scaffolding".
|
446
|
+
|
447
|
+
Some fields use locale strings to drive their `options`. In the `tangible_things.en.yml` template file, look for `super_select_value`, `multiple_option_values` and others.
|
448
|
+
|
449
|
+
You'll notice `&` and `*` symbols prefixing some special keys in the `yml` file. Those are anchors and aliases and they help you reduce repetition in your locale strings.
|
450
|
+
|
451
|
+
To learn more about how these locales are generated in Bullet Train, see the documentation on [Bullet Train's Super Scaffolding](/docs/super-scaffolding.md)
|
452
|
+
|
453
|
+
## 4. Partials that require special instructions, exclusions
|
454
|
+
|
455
|
+
### For using boolean-type fields (options, buttons)
|
456
|
+
|
457
|
+
In `ApplicationController`, add this:
|
458
|
+
|
459
|
+
```ruby
|
460
|
+
include Fields::ControllerSupport
|
461
|
+
```
|
462
|
+
|
463
|
+
### For the file_field partial
|
464
|
+
|
465
|
+
```ruby
|
466
|
+
# in the model
|
467
|
+
has_one_attached :file_field_value
|
468
|
+
after_validation :remove_file_field_value, if: :file_field_value_removal?
|
469
|
+
attr_accessor :file_field_value_removal
|
470
|
+
def file_field_value_removal?
|
471
|
+
def remove_file_field_value
|
472
|
+
```
|
473
|
+
|
474
|
+
```ruby
|
475
|
+
# in the controller's strong_params
|
476
|
+
:file_field_value,
|
477
|
+
:file_field_value_removal,
|
478
|
+
```
|
479
|
+
|
480
|
+
### For `image`, `active_storage_image`
|
481
|
+
|
482
|
+
See [`account/users_helper` in BT core repo](https://github.com/bullet-train-co/bullet_train-core/blob/main/bullet_train/app/helpers/account/users_helper.rb) for implementing `photo_url_for_active_storage_attachment`
|
483
|
+
|
484
|
+
## 5. Modifying ejected partials
|
485
|
+
|
486
|
+
### For ejecting a theme partial and modifying it
|
487
|
+
|
488
|
+
We recommend firing up a Bullet-Train project and using its `bin/resolve` (see docs on [Indirection](indirection)) to get a copy of the partial field locally to modify.
|
@@ -0,0 +1,301 @@
|
|
1
|
+
# Installing Bullet-Train Themes on Other Rails Projects
|
2
|
+
|
3
|
+
Bullet Train themes can be installed on Vanilla Rails projects.
|
4
|
+
|
5
|
+
Our main theme, called `Light`, uses `erb` partials to give you native Rails views with Hotwire-powered components. It's built on `tailwindcss`, uses `postcss` to allow for local CSS overrides and uses `esbuild` for fast javascript compilation and to support javascript-side CSS imports.
|
6
|
+
|
7
|
+
In addition to providing a nice set of UI components, you'll get access to [`nice_partials`](https://github.com/bullet-train-co/nice_partials), Bullet-Train's own lightweight answer for creating `erb` partials with ad-hoc named content areas, which we think is just the right amount of magic for making `erb`-based components.
|
8
|
+
|
9
|
+
Note: we have [special instructions for installing themes on Jumpstart PRO projects](on-jumpstart-pro-projects.md).
|
10
|
+
|
11
|
+
**Contents:**
|
12
|
+
|
13
|
+
1. Installation Instructions
|
14
|
+
2. Optional Configurations for switching colors, theme gems
|
15
|
+
3. Using Locales for fields on new models
|
16
|
+
4. Partials that require special instructions, exclusions
|
17
|
+
5. Modifying ejected partials
|
18
|
+
|
19
|
+
## 1. Installation Instructions
|
20
|
+
|
21
|
+
### Ensure your Rails Project uses `esbuild` and `tailwindcss` with `postcss`
|
22
|
+
|
23
|
+
You'll need to make sure your Rails project is set up to use `esbuild`, `tailwindcss` and `postcss`.
|
24
|
+
|
25
|
+
The easiest way to see what your project should include is to create a separate project, for reference, generated via this command:
|
26
|
+
|
27
|
+
```
|
28
|
+
rails new rails-new-esbuild-tailwind-postcss --css tailwind --javascript esbuild
|
29
|
+
```
|
30
|
+
|
31
|
+
### Add the theme gem
|
32
|
+
|
33
|
+
These instructions assume you're installing the `Light` theme bundled with Bullet Train.
|
34
|
+
|
35
|
+
```
|
36
|
+
bundle add bullet_train-themes-light
|
37
|
+
```
|
38
|
+
|
39
|
+
Or add the following to your `Gemfile`:
|
40
|
+
|
41
|
+
```
|
42
|
+
gem "bullet_train-themes-light"
|
43
|
+
```
|
44
|
+
|
45
|
+
And then run:
|
46
|
+
|
47
|
+
```
|
48
|
+
bundle install
|
49
|
+
```
|
50
|
+
|
51
|
+
### Add `npm` packages
|
52
|
+
|
53
|
+
The `Light` theme requires the following npm packages to be installed
|
54
|
+
|
55
|
+
```
|
56
|
+
yarn add @bullet-train/bullet-train @bullet-train/fields autoprefixer @rails/actiontext postcss-extend-rule postcss-import
|
57
|
+
```
|
58
|
+
|
59
|
+
Update your `app/javascript/controllers/index.js` with the following lines:
|
60
|
+
|
61
|
+
```js
|
62
|
+
import { controllerDefinitions as bulletTrainControllers } from "@bullet-train/bullet-train"
|
63
|
+
import { controllerDefinitions as bulletTrainFieldControllers } from "@bullet-train/fields"
|
64
|
+
|
65
|
+
application.load(bulletTrainControllers)
|
66
|
+
application.load(bulletTrainFieldControllers)
|
67
|
+
```
|
68
|
+
|
69
|
+
### Overwrite tailwind and esbuild config files, add bin stubs from Bullet Train
|
70
|
+
|
71
|
+
```
|
72
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/esbuild.config.js" -o esbuild.config.js
|
73
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/postcss.config.js" -o postcss.config.js
|
74
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/tailwind.config.js" -o tailwind.config.js
|
75
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/bin/theme" -o bin/theme
|
76
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/bin/link" -o bin/link
|
77
|
+
chmod +x bin/theme bin/link
|
78
|
+
|
79
|
+
```
|
80
|
+
|
81
|
+
### Update `build:css` in `package.json`
|
82
|
+
|
83
|
+
In `package.json`, replace the `build` and `build:css` entries under `scripts` with:
|
84
|
+
|
85
|
+
```json
|
86
|
+
"build": "THEME=\"light\" node esbuild.config.js",
|
87
|
+
"build:css": "bin/link; THEME=\"light\" tailwindcss --postcss --minify -c ./tailwind.config.js -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.tailwind.css"
|
88
|
+
```
|
89
|
+
### Update esbuild.config.js
|
90
|
+
|
91
|
+
Remove or comment out the following line from `esbuild.config.js`:
|
92
|
+
|
93
|
+
```js
|
94
|
+
"intl-tel-input-utils": path.join(process.cwd(), "app/javascript/intl-tel-input-utils.js"),
|
95
|
+
```
|
96
|
+
|
97
|
+
### Add `stylesheet_link_tag` to `<head>`
|
98
|
+
|
99
|
+
Make sure you have the following three lines in your `<head>`, which should be defined in `app/views/layouts/application.html.erb`:
|
100
|
+
|
101
|
+
```erb
|
102
|
+
<%= stylesheet_link_tag "application", media: "all", "data-turbo-track": "reload" %>
|
103
|
+
<%= stylesheet_link_tag "application.tailwind", media: "all", "data-turbo-track": "reload" %>
|
104
|
+
<%= javascript_include_tag 'application.light', 'data-turbo-track': 'reload' %>
|
105
|
+
```
|
106
|
+
|
107
|
+
### Import the Theme Style Sheet
|
108
|
+
|
109
|
+
To your `application.tailwind.css` file, add the following line:
|
110
|
+
|
111
|
+
```css
|
112
|
+
@import "$ThemeStylesheetsDir/application.css";
|
113
|
+
```
|
114
|
+
|
115
|
+
Also be sure to replace the following lines:
|
116
|
+
|
117
|
+
```css
|
118
|
+
@tailwind base;
|
119
|
+
@tailwind components;
|
120
|
+
@tailwind utilities;
|
121
|
+
```
|
122
|
+
|
123
|
+
To the following lines:
|
124
|
+
|
125
|
+
```css
|
126
|
+
@import "tailwindcss/base";
|
127
|
+
@import "tailwindcss/components";
|
128
|
+
@import "tailwindcss/utilities";
|
129
|
+
```
|
130
|
+
|
131
|
+
Unless this is done, `postcss-import` doesn't work correctly.
|
132
|
+
|
133
|
+
### Add Themify Icons, jQuery (for now) and trix editor support
|
134
|
+
|
135
|
+
Note: jQuery is needed for some of our components, but defining `window.$` won't be required soon. See PR https://github.com/bullet-train-co/bullet_train-core/pull/765
|
136
|
+
|
137
|
+
```
|
138
|
+
yarn add @icon/themify-icons jquery
|
139
|
+
```
|
140
|
+
|
141
|
+
To your `application.js`, add the following line:
|
142
|
+
|
143
|
+
```js
|
144
|
+
import jquery from "jquery"
|
145
|
+
window.jQuery = jquery
|
146
|
+
window.$ = jquery
|
147
|
+
|
148
|
+
require("@icon/themify-icons/themify-icons.css")
|
149
|
+
|
150
|
+
import { trixEditor } from "@bullet-train/fields"
|
151
|
+
trixEditor()
|
152
|
+
```
|
153
|
+
|
154
|
+
### Add Locale Strings
|
155
|
+
|
156
|
+
Add these to your `config/locales/en.yml` under `en:`
|
157
|
+
|
158
|
+
```yml
|
159
|
+
date:
|
160
|
+
formats:
|
161
|
+
date_field: "%m/%d/%Y"
|
162
|
+
date_and_time_field: "%m/%d/%Y %l:%M %p"
|
163
|
+
date_controller: "MM/DD/YYYY"
|
164
|
+
time:
|
165
|
+
am: AM
|
166
|
+
pm: PM
|
167
|
+
formats:
|
168
|
+
date_field: "%m/%d/%Y"
|
169
|
+
date_and_time_field: "%m/%d/%Y %l:%M %p"
|
170
|
+
date_controller: "MM/DD/YYYY h:mm A"
|
171
|
+
daterangepicker:
|
172
|
+
firstDay: 1
|
173
|
+
separator: " - "
|
174
|
+
applyLabel: "Apply"
|
175
|
+
cancelLabel: "Cancel"
|
176
|
+
fromLabel: "From"
|
177
|
+
toLabel: "To"
|
178
|
+
customRangeLabel: "Custom"
|
179
|
+
weekLabel: "W"
|
180
|
+
daysOfWeek:
|
181
|
+
- "Su"
|
182
|
+
- "Mo"
|
183
|
+
- "Tu"
|
184
|
+
- "We"
|
185
|
+
- "Th"
|
186
|
+
- "Fr"
|
187
|
+
- "Sa"
|
188
|
+
monthNames:
|
189
|
+
- "January"
|
190
|
+
- "February"
|
191
|
+
- "March"
|
192
|
+
- "April"
|
193
|
+
- "May"
|
194
|
+
- "June"
|
195
|
+
- "July"
|
196
|
+
- "August"
|
197
|
+
- "September"
|
198
|
+
- "October"
|
199
|
+
- "November"
|
200
|
+
- "December"
|
201
|
+
date_range_controller:
|
202
|
+
today: Today
|
203
|
+
yesterday: yesterday
|
204
|
+
last7Days: Last 7 Days
|
205
|
+
last30Days: Last 30 Days
|
206
|
+
thisMonth: This Month
|
207
|
+
lastMonth: Last Month
|
208
|
+
global:
|
209
|
+
buttons:
|
210
|
+
other: Other
|
211
|
+
cancel: Cancel
|
212
|
+
bulk_select:
|
213
|
+
all: All
|
214
|
+
```
|
215
|
+
|
216
|
+
## 2. Optional Configurations for switching colors, theme gems
|
217
|
+
|
218
|
+
### For Setting the Active Color
|
219
|
+
|
220
|
+
```
|
221
|
+
curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train/main/initializers/theme.rb" -o initializers/theme.rb
|
222
|
+
```
|
223
|
+
|
224
|
+
Add the following classes to your `html` tag for your layout:
|
225
|
+
|
226
|
+
```erb
|
227
|
+
<html class="theme-<%= BulletTrain::Themes::Light.color %> <%= "theme-secondary-#{BulletTrain::Themes::Light.secondary_color}" if BulletTrain::Themes::Light.secondary_color %>"
|
228
|
+
```
|
229
|
+
|
230
|
+
### For Switching Between Installed Themes
|
231
|
+
|
232
|
+
If you'd like to create your own theme but would still like to build on top of `:light`, you'll need to have both gems installed and you'll be able to switch the current theme this way.
|
233
|
+
|
234
|
+
Define `current_theme` in `app/helpers/application_helper.rb`
|
235
|
+
|
236
|
+
```
|
237
|
+
module ApplicationHelper
|
238
|
+
def current_theme
|
239
|
+
:light
|
240
|
+
end
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
To change to use a different theme:
|
245
|
+
|
246
|
+
1. Change the value returned by `current_theme` to the new theme name
|
247
|
+
2. Change the name of the `THEME` env var defined in `build` and `build:css` in `package.json`
|
248
|
+
3. Change the name of the theme in the `javascript_include_tag` in the `<head>`.
|
249
|
+
|
250
|
+
## 3. Using Locales for fields on new models
|
251
|
+
|
252
|
+
The theme's field partials work best with locale strings that are defined for the model you're creating.
|
253
|
+
|
254
|
+
Example: you've created a Project model. Here we'll create a `projects.en.yml`
|
255
|
+
|
256
|
+
1. Run `curl -L "https://raw.githubusercontent.com/bullet-train-co/bullet_train-core/main/bullet_train-super_scaffolding/config/locales/en/scaffolding/completely_concrete/tangible_things.en.yml" -o config/locales/projects.en.yml`
|
257
|
+
2. Search and replace `projects.en.yml` for `scaffolding/completely_concrete/tangible_things`, `Tangible Things`, `Tangible Thing`, `tangible_things` and `tangible_thing`. Replace with `projects`, `Projects`, `Project`, `projects` and `project` respectively.
|
258
|
+
3. Remove strings you won't be using. In particular, look for comments with "skip" or "scaffolding".
|
259
|
+
|
260
|
+
Some fields use locale strings to drive their `options`. In the `tangible_things.en.yml` template file, look for `super_select_value`, `multiple_option_values` and others.
|
261
|
+
|
262
|
+
You'll notice `&` and `*` symbols prefixing some special keys in the `yml` file. Those are anchors and aliases and they help you reduce repetition in your locale strings.
|
263
|
+
|
264
|
+
To learn more about how these locales are generated in Bullet Train, see the documentation on [Bullet Train's Super Scaffolding](/docs/super-scaffolding.md)
|
265
|
+
|
266
|
+
## 4. Partials that require special instructions, exclusions
|
267
|
+
|
268
|
+
### For using boolean-type fields (options, buttons)
|
269
|
+
|
270
|
+
In `ApplicationController`, add this:
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
include Fields::ControllerSupport
|
274
|
+
```
|
275
|
+
|
276
|
+
### For the file_field partial
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
# in the model
|
280
|
+
has_one_attached :file_field_value
|
281
|
+
after_validation :remove_file_field_value, if: :file_field_value_removal?
|
282
|
+
attr_accessor :file_field_value_removal
|
283
|
+
def file_field_value_removal?
|
284
|
+
def remove_file_field_value
|
285
|
+
```
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
# in the controller's strong_params
|
289
|
+
:file_field_value,
|
290
|
+
:file_field_value_removal,
|
291
|
+
```
|
292
|
+
|
293
|
+
### For `image`, `active_storage_image`
|
294
|
+
|
295
|
+
See [`account/users_helper` in BT core repo](https://github.com/bullet-train-co/bullet_train-core/blob/main/bullet_train/app/helpers/account/users_helper.rb) for implementing `photo_url_for_active_storage_attachment`
|
296
|
+
|
297
|
+
## 5. Modifying ejected partials
|
298
|
+
|
299
|
+
### For ejecting a theme partial and modifying it
|
300
|
+
|
301
|
+
We recommend firing up a Bullet-Train project and using its `bin/resolve` (see docs on [Indirection](indirection)) to get a copy of the partial field locally to modify.
|
data/docs/themes.md
CHANGED
@@ -79,3 +79,8 @@ This allows the theme engine to resolve which theme in the inheritance chain wil
|
|
79
79
|
### Let your designer name their theme.
|
80
80
|
|
81
81
|
You're going to have to call your theme something and there are practical reasons to not call it something generic. If you're pursuing a heavily customized design, consider allowing the designer or designers who are creating the look-and-feel of your application to name their own masterpiece. Giving it a distinct name will really help differentiate things when you're ready to start introducing additional facets to your application or a totally new look-and-feel down the road.
|
82
|
+
|
83
|
+
## Additional Themes Documentation
|
84
|
+
|
85
|
+
* [Installing Bullet-Train Themes on Other Rails Projects](/docs/themes/on-other-rails-projects.md)
|
86
|
+
* [Installing Bullet-Train Themes on Jumpstart PRO Projects](/docs/themes/on-jumpstart-pro-projects.md)
|
data/lib/bullet_train/version.rb
CHANGED
@@ -1,32 +1,5 @@
|
|
1
1
|
require "io/wait"
|
2
2
|
|
3
|
-
namespace :bt do
|
4
|
-
desc "Symlink registered gems in `./tmp/gems` so their views, etc. can be inspected by Tailwind CSS."
|
5
|
-
task link: :environment do
|
6
|
-
if Dir.exist?("tmp/gems")
|
7
|
-
puts "Removing previously linked gems."
|
8
|
-
`rm -f tmp/gems/*`
|
9
|
-
else
|
10
|
-
if File.exist?("tmp/gems")
|
11
|
-
raise "A file named `tmp/gems` already exists? It has to be removed before we can create the required directory."
|
12
|
-
end
|
13
|
-
|
14
|
-
puts "Creating 'tmp/gems' directory."
|
15
|
-
`mkdir tmp/gems`
|
16
|
-
end
|
17
|
-
|
18
|
-
`touch tmp/gems/.keep`
|
19
|
-
|
20
|
-
BulletTrain.linked_gems.each do |linked_gem|
|
21
|
-
target = `bundle show #{linked_gem}`.chomp
|
22
|
-
if target.present?
|
23
|
-
puts "Linking '#{linked_gem}' to '#{target}'."
|
24
|
-
`ln -s #{target} tmp/gems/#{linked_gem}`
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
3
|
namespace :bullet_train do
|
31
4
|
desc "Figure out where something is coming from."
|
32
5
|
task :resolve, [:all_options] => :environment do |t, arguments|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.31
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -539,8 +539,6 @@ files:
|
|
539
539
|
- app/controllers/registrations_controller.rb
|
540
540
|
- app/controllers/sessions_controller.rb
|
541
541
|
- app/helpers/account/buttons_helper.rb
|
542
|
-
- app/helpers/account/dates_helper.rb
|
543
|
-
- app/helpers/account/forms_helper.rb
|
544
542
|
- app/helpers/account/invitations_helper.rb
|
545
543
|
- app/helpers/account/locale_helper.rb
|
546
544
|
- app/helpers/account/markdown_helper.rb
|
@@ -549,11 +547,9 @@ files:
|
|
549
547
|
- app/helpers/account/role_helper.rb
|
550
548
|
- app/helpers/account/teams_helper.rb
|
551
549
|
- app/helpers/account/users_helper.rb
|
552
|
-
- app/helpers/attributes_helper.rb
|
553
550
|
- app/helpers/base_helper.rb
|
554
551
|
- app/helpers/concerns/helpers/base.rb
|
555
552
|
- app/helpers/email_helper.rb
|
556
|
-
- app/helpers/images_helper.rb
|
557
553
|
- app/helpers/invitation_only_helper.rb
|
558
554
|
- app/helpers/invitations_helper.rb
|
559
555
|
- app/javascript/controllers/bulk_action_form_controller.js
|
@@ -757,6 +753,8 @@ files:
|
|
757
753
|
- docs/teams.md
|
758
754
|
- docs/testing.md
|
759
755
|
- docs/themes.md
|
756
|
+
- docs/themes/on-jumpstart-pro-projects.md
|
757
|
+
- docs/themes/on-other-rails-projects.md
|
760
758
|
- docs/trademark.md
|
761
759
|
- docs/tunneling.md
|
762
760
|
- docs/upgrades.md
|
@@ -1,70 +0,0 @@
|
|
1
|
-
module Account::DatesHelper
|
2
|
-
def display_date(timestamp, custom_date_format = nil, format: :default, date_format: nil)
|
3
|
-
return nil unless timestamp
|
4
|
-
format = date_format if date_format
|
5
|
-
|
6
|
-
if format && format == :default
|
7
|
-
# e.g. October 11, 2018
|
8
|
-
if custom_date_format
|
9
|
-
local_time(timestamp).strftime(custom_date_format)
|
10
|
-
elsif local_time(timestamp).year == local_time(Time.now).year
|
11
|
-
local_time(timestamp).strftime("%B %-d")
|
12
|
-
else
|
13
|
-
local_time(timestamp).strftime("%B %-d, %Y")
|
14
|
-
end
|
15
|
-
else
|
16
|
-
localize(local_time(timestamp).to_date, format: format)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def display_time(timestamp, custom_time_format = nil, format: :default, time_format: nil)
|
21
|
-
return nil unless timestamp
|
22
|
-
format = time_format if time_format
|
23
|
-
|
24
|
-
if format && format == :default
|
25
|
-
# e.g. 4:22 PM
|
26
|
-
local_time(timestamp).strftime(custom_time_format || "%l:%M %p")
|
27
|
-
else
|
28
|
-
localize(local_time(timestamp).to_time, format: format)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def display_date_and_time(timestamp, custom_date_format = nil, custom_time_format = nil, format: :default, date_format: nil, time_format: nil)
|
33
|
-
return nil unless timestamp
|
34
|
-
format = "#{date_format} #{time_format}" if date_format && time_format
|
35
|
-
|
36
|
-
if format && format == :default
|
37
|
-
# e.g. Today at 4:22 PM
|
38
|
-
# e.g. Yesterday at 2:12 PM
|
39
|
-
# e.g. April 24 at 7:39 AM
|
40
|
-
# today?
|
41
|
-
if local_time(timestamp).to_date == local_time(Time.now).to_date
|
42
|
-
"Today at #{display_time(timestamp, custom_time_format)}"
|
43
|
-
# yesterday?
|
44
|
-
elsif (local_time(timestamp).to_date) == (local_time(Time.now).to_date - 1.day)
|
45
|
-
"Yesterday at #{display_time(timestamp, custom_time_format)}"
|
46
|
-
else
|
47
|
-
"#{display_date(timestamp, custom_date_format)} at #{display_time(timestamp, custom_time_format)}"
|
48
|
-
end
|
49
|
-
else
|
50
|
-
localize(local_time(timestamp).to_datetime, format: format)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def local_time(timestamp)
|
55
|
-
timestamp&.in_time_zone(current_user.time_zone)
|
56
|
-
end
|
57
|
-
|
58
|
-
def am_pm?
|
59
|
-
!"#{I18n.t("time.am", fallback: false, default: "")}#{I18n.t("time.pm", fallback: false, default: "")}".empty?
|
60
|
-
end
|
61
|
-
|
62
|
-
def time_zone_name_to_id
|
63
|
-
ActiveSupport::TimeZone.all.map { |tz| {tz.name.to_s => tz.tzinfo.name} }.reduce({}, :merge)
|
64
|
-
end
|
65
|
-
|
66
|
-
def current_time_zone
|
67
|
-
current_time_zone_name = current_user&.time_zone || current_user&.current_team&.time_zone || "UTC"
|
68
|
-
ActiveSupport::TimeZone.find_tzinfo(current_time_zone_name).name
|
69
|
-
end
|
70
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
module Account::FormsHelper
|
2
|
-
PRESENCE_VALIDATORS = [ActiveRecord::Validations::PresenceValidator, ActiveModel::Validations::PresenceValidator]
|
3
|
-
|
4
|
-
def presence_validated?(object, attribute)
|
5
|
-
validators = object.class.validators
|
6
|
-
validators.select! do |validator|
|
7
|
-
PRESENCE_VALIDATORS.include?(validator.class) && validator.attributes.include?(attribute)
|
8
|
-
end
|
9
|
-
validators.any?
|
10
|
-
end
|
11
|
-
|
12
|
-
def flush_content_for(name)
|
13
|
-
content_for name, flush: true do
|
14
|
-
""
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def options_with_labels(options, namespace)
|
19
|
-
hash = {}
|
20
|
-
options.each do |option|
|
21
|
-
hash[option] = t([namespace, option].join("."))
|
22
|
-
end
|
23
|
-
hash
|
24
|
-
end
|
25
|
-
|
26
|
-
def if_present(string)
|
27
|
-
string.present? ? string : nil
|
28
|
-
end
|
29
|
-
|
30
|
-
def model_key(form)
|
31
|
-
form.object.class.name.pluralize.underscore
|
32
|
-
end
|
33
|
-
|
34
|
-
def labels_for(form, method)
|
35
|
-
keys = [:placeholder, :label, :help, :options_help]
|
36
|
-
path = [model_key(form), (current_fields_namespace || :fields), method].compact
|
37
|
-
Struct.new(*keys).new(*keys.map { |key| t((path + [key]).join("."), default: "").presence })
|
38
|
-
end
|
39
|
-
|
40
|
-
def options_for(form, method)
|
41
|
-
# e.g. "scaffolding/completely_concrete/tangible_things.fields.text_area_value.options"
|
42
|
-
path = [model_key(form), (current_fields_namespace || :fields), method, :options]
|
43
|
-
options = t(path.compact.join("."))
|
44
|
-
return options unless options.is_a?(Hash)
|
45
|
-
options.stringify_keys
|
46
|
-
end
|
47
|
-
|
48
|
-
def legacy_label_for(form, method)
|
49
|
-
# e.g. 'scaffolding/things.labels.name'
|
50
|
-
key = "#{model_key(form)}.labels.#{method}"
|
51
|
-
# e.g. 'scaffolding/things.labels.name' or 'scaffolding.things.labels.name' or nil
|
52
|
-
t(key, default: "").presence || t(key.tr("/", "."), default: "").presence
|
53
|
-
end
|
54
|
-
|
55
|
-
def within_fields_namespace(namespace)
|
56
|
-
@fields_namespaces ||= []
|
57
|
-
@fields_namespaces << namespace
|
58
|
-
yield
|
59
|
-
@fields_namespaces.pop
|
60
|
-
end
|
61
|
-
|
62
|
-
def current_fields_namespace
|
63
|
-
@fields_namespaces&.last
|
64
|
-
end
|
65
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module AttributesHelper
|
2
|
-
def current_attributes_object
|
3
|
-
@_current_attribute_settings&.dig(:object)
|
4
|
-
end
|
5
|
-
|
6
|
-
def current_attributes_strategy
|
7
|
-
@_current_attribute_settings&.dig(:strategy)
|
8
|
-
end
|
9
|
-
|
10
|
-
def with_attribute_settings(object: current_attributes_object, strategy: current_attributes_strategy)
|
11
|
-
old_attribute_settings = @_current_attribute_settings
|
12
|
-
@_current_attribute_settings = {object: object, strategy: strategy}
|
13
|
-
yield
|
14
|
-
ensure
|
15
|
-
@_current_attribute_settings = old_attribute_settings
|
16
|
-
end
|
17
|
-
end
|