bootstrap5-rails-extensions 0.1.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 +7 -0
- data/.gitignore +15 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +221 -0
- data/LICENSE.txt +21 -0
- data/README.md +192 -0
- data/Rakefile +6 -0
- data/app/helpers/bootstrap5_rails_extensions/card_helper.rb +143 -0
- data/app/helpers/bootstrap5_rails_extensions/modal_helper.rb +227 -0
- data/app/helpers/bootstrap5_rails_extensions/offcanvas_helper.rb +67 -0
- data/app/helpers/bootstrap5_rails_extensions/table_helper.rb +93 -0
- data/app/helpers/bootstrap5_rails_extensions/toast_helper.rb +33 -0
- data/app/javascript/bootstrap5_rails_extensions/modal_controller.js +88 -0
- data/app/javascript/bootstrap5_rails_extensions/offcanvas_controller.js +62 -0
- data/app/javascript/bootstrap5_rails_extensions/toast_controller.js +31 -0
- data/app/views/bootstrap5_rails_extensions/_modal.html.erb +6 -0
- data/app/views/bootstrap5_rails_extensions/_offcanvas.html.erb +15 -0
- data/app/views/bootstrap5_rails_extensions/_toast.html.erb +15 -0
- data/bin/console +12 -0
- data/bin/setup +8 -0
- data/bootstrap5_rails_extensions.gemspec +46 -0
- data/lib/bootstrap5/rails/extensions.rb +3 -0
- data/lib/bootstrap5_rails_extensions/engine.rb +32 -0
- data/lib/bootstrap5_rails_extensions/turbo_stream_toast.rb +42 -0
- data/lib/bootstrap5_rails_extensions/version.rb +5 -0
- data/lib/bootstrap5_rails_extensions.rb +5 -0
- metadata +83 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d474e088c4e028c5086730e93991c25b52559a7851469d5b27ef648c569418b4
|
|
4
|
+
data.tar.gz: 7e376d17ad4dbadba15b41cfb7010575d69dabfee2f494f6f3fb1df2ed9e5770
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a4d051ba8ca01298ae82f600974f3021ac1786f5ff50dd64546fe18bcbd2549ecdf2c6f56210b6b84f7521cb84203c801a759a14cbe85ac39d8d5350f3feb954
|
|
7
|
+
data.tar.gz: c6a9ba17cea83be96fecb56e2a04b1074132117c46b6daaad85a602552c26e0d67abbfbd6ebb5194a485a0951f9a30ef971d9b8219f281c53ceff2e8c327f061
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
bootstrap5-rails-extensions (0.1.0)
|
|
5
|
+
rails (>= 8.0)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
actioncable (8.0.3)
|
|
11
|
+
actionpack (= 8.0.3)
|
|
12
|
+
activesupport (= 8.0.3)
|
|
13
|
+
nio4r (~> 2.0)
|
|
14
|
+
websocket-driver (>= 0.6.1)
|
|
15
|
+
zeitwerk (~> 2.6)
|
|
16
|
+
actionmailbox (8.0.3)
|
|
17
|
+
actionpack (= 8.0.3)
|
|
18
|
+
activejob (= 8.0.3)
|
|
19
|
+
activerecord (= 8.0.3)
|
|
20
|
+
activestorage (= 8.0.3)
|
|
21
|
+
activesupport (= 8.0.3)
|
|
22
|
+
mail (>= 2.8.0)
|
|
23
|
+
actionmailer (8.0.3)
|
|
24
|
+
actionpack (= 8.0.3)
|
|
25
|
+
actionview (= 8.0.3)
|
|
26
|
+
activejob (= 8.0.3)
|
|
27
|
+
activesupport (= 8.0.3)
|
|
28
|
+
mail (>= 2.8.0)
|
|
29
|
+
rails-dom-testing (~> 2.2)
|
|
30
|
+
actionpack (8.0.3)
|
|
31
|
+
actionview (= 8.0.3)
|
|
32
|
+
activesupport (= 8.0.3)
|
|
33
|
+
nokogiri (>= 1.8.5)
|
|
34
|
+
rack (>= 2.2.4)
|
|
35
|
+
rack-session (>= 1.0.1)
|
|
36
|
+
rack-test (>= 0.6.3)
|
|
37
|
+
rails-dom-testing (~> 2.2)
|
|
38
|
+
rails-html-sanitizer (~> 1.6)
|
|
39
|
+
useragent (~> 0.16)
|
|
40
|
+
actiontext (8.0.3)
|
|
41
|
+
actionpack (= 8.0.3)
|
|
42
|
+
activerecord (= 8.0.3)
|
|
43
|
+
activestorage (= 8.0.3)
|
|
44
|
+
activesupport (= 8.0.3)
|
|
45
|
+
globalid (>= 0.6.0)
|
|
46
|
+
nokogiri (>= 1.8.5)
|
|
47
|
+
actionview (8.0.3)
|
|
48
|
+
activesupport (= 8.0.3)
|
|
49
|
+
builder (~> 3.1)
|
|
50
|
+
erubi (~> 1.11)
|
|
51
|
+
rails-dom-testing (~> 2.2)
|
|
52
|
+
rails-html-sanitizer (~> 1.6)
|
|
53
|
+
activejob (8.0.3)
|
|
54
|
+
activesupport (= 8.0.3)
|
|
55
|
+
globalid (>= 0.3.6)
|
|
56
|
+
activemodel (8.0.3)
|
|
57
|
+
activesupport (= 8.0.3)
|
|
58
|
+
activerecord (8.0.3)
|
|
59
|
+
activemodel (= 8.0.3)
|
|
60
|
+
activesupport (= 8.0.3)
|
|
61
|
+
timeout (>= 0.4.0)
|
|
62
|
+
activestorage (8.0.3)
|
|
63
|
+
actionpack (= 8.0.3)
|
|
64
|
+
activejob (= 8.0.3)
|
|
65
|
+
activerecord (= 8.0.3)
|
|
66
|
+
activesupport (= 8.0.3)
|
|
67
|
+
marcel (~> 1.0)
|
|
68
|
+
activesupport (8.0.3)
|
|
69
|
+
base64
|
|
70
|
+
benchmark (>= 0.3)
|
|
71
|
+
bigdecimal
|
|
72
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
73
|
+
connection_pool (>= 2.2.5)
|
|
74
|
+
drb
|
|
75
|
+
i18n (>= 1.6, < 2)
|
|
76
|
+
logger (>= 1.4.2)
|
|
77
|
+
minitest (>= 5.1)
|
|
78
|
+
securerandom (>= 0.3)
|
|
79
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
80
|
+
uri (>= 0.13.1)
|
|
81
|
+
base64 (0.3.0)
|
|
82
|
+
benchmark (0.4.1)
|
|
83
|
+
bigdecimal (3.2.3)
|
|
84
|
+
builder (3.3.0)
|
|
85
|
+
concurrent-ruby (1.3.5)
|
|
86
|
+
connection_pool (2.5.4)
|
|
87
|
+
crass (1.0.6)
|
|
88
|
+
date (3.4.1)
|
|
89
|
+
drb (2.2.3)
|
|
90
|
+
erb (5.0.2)
|
|
91
|
+
erubi (1.13.1)
|
|
92
|
+
globalid (1.3.0)
|
|
93
|
+
activesupport (>= 6.1)
|
|
94
|
+
i18n (1.14.7)
|
|
95
|
+
concurrent-ruby (~> 1.0)
|
|
96
|
+
io-console (0.8.1)
|
|
97
|
+
irb (1.15.2)
|
|
98
|
+
pp (>= 0.6.0)
|
|
99
|
+
rdoc (>= 4.0.0)
|
|
100
|
+
reline (>= 0.4.2)
|
|
101
|
+
logger (1.7.0)
|
|
102
|
+
loofah (2.24.1)
|
|
103
|
+
crass (~> 1.0.2)
|
|
104
|
+
nokogiri (>= 1.12.0)
|
|
105
|
+
mail (2.8.1)
|
|
106
|
+
mini_mime (>= 0.1.1)
|
|
107
|
+
net-imap
|
|
108
|
+
net-pop
|
|
109
|
+
net-smtp
|
|
110
|
+
marcel (1.1.0)
|
|
111
|
+
mini_mime (1.1.5)
|
|
112
|
+
minitest (5.25.5)
|
|
113
|
+
net-imap (0.5.11)
|
|
114
|
+
date
|
|
115
|
+
net-protocol
|
|
116
|
+
net-pop (0.1.2)
|
|
117
|
+
net-protocol
|
|
118
|
+
net-protocol (0.2.2)
|
|
119
|
+
timeout
|
|
120
|
+
net-smtp (0.5.1)
|
|
121
|
+
net-protocol
|
|
122
|
+
nio4r (2.7.4)
|
|
123
|
+
nokogiri (1.18.10-aarch64-linux-gnu)
|
|
124
|
+
racc (~> 1.4)
|
|
125
|
+
nokogiri (1.18.10-aarch64-linux-musl)
|
|
126
|
+
racc (~> 1.4)
|
|
127
|
+
nokogiri (1.18.10-arm-linux-gnu)
|
|
128
|
+
racc (~> 1.4)
|
|
129
|
+
nokogiri (1.18.10-arm-linux-musl)
|
|
130
|
+
racc (~> 1.4)
|
|
131
|
+
nokogiri (1.18.10-arm64-darwin)
|
|
132
|
+
racc (~> 1.4)
|
|
133
|
+
nokogiri (1.18.10-x86_64-darwin)
|
|
134
|
+
racc (~> 1.4)
|
|
135
|
+
nokogiri (1.18.10-x86_64-linux-gnu)
|
|
136
|
+
racc (~> 1.4)
|
|
137
|
+
nokogiri (1.18.10-x86_64-linux-musl)
|
|
138
|
+
racc (~> 1.4)
|
|
139
|
+
pp (0.6.2)
|
|
140
|
+
prettyprint
|
|
141
|
+
prettyprint (0.2.0)
|
|
142
|
+
psych (5.2.6)
|
|
143
|
+
date
|
|
144
|
+
stringio
|
|
145
|
+
racc (1.8.1)
|
|
146
|
+
rack (3.2.1)
|
|
147
|
+
rack-session (2.1.1)
|
|
148
|
+
base64 (>= 0.1.0)
|
|
149
|
+
rack (>= 3.0.0)
|
|
150
|
+
rack-test (2.2.0)
|
|
151
|
+
rack (>= 1.3)
|
|
152
|
+
rackup (2.2.1)
|
|
153
|
+
rack (>= 3)
|
|
154
|
+
rails (8.0.3)
|
|
155
|
+
actioncable (= 8.0.3)
|
|
156
|
+
actionmailbox (= 8.0.3)
|
|
157
|
+
actionmailer (= 8.0.3)
|
|
158
|
+
actionpack (= 8.0.3)
|
|
159
|
+
actiontext (= 8.0.3)
|
|
160
|
+
actionview (= 8.0.3)
|
|
161
|
+
activejob (= 8.0.3)
|
|
162
|
+
activemodel (= 8.0.3)
|
|
163
|
+
activerecord (= 8.0.3)
|
|
164
|
+
activestorage (= 8.0.3)
|
|
165
|
+
activesupport (= 8.0.3)
|
|
166
|
+
bundler (>= 1.15.0)
|
|
167
|
+
railties (= 8.0.3)
|
|
168
|
+
rails-dom-testing (2.3.0)
|
|
169
|
+
activesupport (>= 5.0.0)
|
|
170
|
+
minitest
|
|
171
|
+
nokogiri (>= 1.6)
|
|
172
|
+
rails-html-sanitizer (1.6.2)
|
|
173
|
+
loofah (~> 2.21)
|
|
174
|
+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
175
|
+
railties (8.0.3)
|
|
176
|
+
actionpack (= 8.0.3)
|
|
177
|
+
activesupport (= 8.0.3)
|
|
178
|
+
irb (~> 1.13)
|
|
179
|
+
rackup (>= 1.0.0)
|
|
180
|
+
rake (>= 12.2)
|
|
181
|
+
thor (~> 1.0, >= 1.2.2)
|
|
182
|
+
tsort (>= 0.2)
|
|
183
|
+
zeitwerk (~> 2.6)
|
|
184
|
+
rake (13.3.0)
|
|
185
|
+
rdoc (6.15.0)
|
|
186
|
+
erb
|
|
187
|
+
psych (>= 4.0.0)
|
|
188
|
+
tsort
|
|
189
|
+
reline (0.6.2)
|
|
190
|
+
io-console (~> 0.5)
|
|
191
|
+
securerandom (0.4.1)
|
|
192
|
+
stringio (3.1.7)
|
|
193
|
+
thor (1.4.0)
|
|
194
|
+
timeout (0.4.3)
|
|
195
|
+
tsort (0.2.0)
|
|
196
|
+
tzinfo (2.0.6)
|
|
197
|
+
concurrent-ruby (~> 1.0)
|
|
198
|
+
uri (1.0.3)
|
|
199
|
+
useragent (0.16.11)
|
|
200
|
+
websocket-driver (0.8.0)
|
|
201
|
+
base64
|
|
202
|
+
websocket-extensions (>= 0.1.0)
|
|
203
|
+
websocket-extensions (0.1.5)
|
|
204
|
+
zeitwerk (2.7.3)
|
|
205
|
+
|
|
206
|
+
PLATFORMS
|
|
207
|
+
aarch64-linux-gnu
|
|
208
|
+
aarch64-linux-musl
|
|
209
|
+
arm-linux-gnu
|
|
210
|
+
arm-linux-musl
|
|
211
|
+
arm64-darwin
|
|
212
|
+
x86_64-darwin
|
|
213
|
+
x86_64-linux-gnu
|
|
214
|
+
x86_64-linux-musl
|
|
215
|
+
|
|
216
|
+
DEPENDENCIES
|
|
217
|
+
bootstrap5-rails-extensions!
|
|
218
|
+
rake (~> 13.0)
|
|
219
|
+
|
|
220
|
+
BUNDLED WITH
|
|
221
|
+
2.7.2
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Dreaw Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Bootstrap5 Rails Extensions(Rails Engine)
|
|
2
|
+
|
|
3
|
+
RailsアプリケーションでBootstrap 5をTurbo/Stimulusと併用しやすくするための拡張を提供します。モーダルやオフキャンバス、カード、テーブル、トースト向けのDSLヘルパーと、対応するStimulusコントローラを同梱しています。
|
|
4
|
+
|
|
5
|
+
## インストール
|
|
6
|
+
|
|
7
|
+
Gemfile(ホストアプリ):
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "bootstrap5-rails-extensions"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`bundle install` を実行してください。
|
|
14
|
+
|
|
15
|
+
## セットアップ
|
|
16
|
+
|
|
17
|
+
### Stimulusコントローラの登録
|
|
18
|
+
|
|
19
|
+
Importmapをご利用の場合は、エンジンが提供するコントローラ群をpinしてください。
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
# config/importmap.rb
|
|
23
|
+
pin_all_from "bootstrap5_rails_extensions", under: "bootstrap5_rails_extensions"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Stimulusアプリケーションへの登録例です。
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
// app/javascript/controllers/index.js
|
|
30
|
+
import { application } from "./application"
|
|
31
|
+
|
|
32
|
+
import ModalController from "bootstrap5_rails_extensions/modal_controller"
|
|
33
|
+
import OffcanvasController from "bootstrap5_rails_extensions/offcanvas_controller"
|
|
34
|
+
import ToastController from "bootstrap5_rails_extensions/toast_controller"
|
|
35
|
+
|
|
36
|
+
application.register("modal", ModalController)
|
|
37
|
+
application.register("offcanvas", OffcanvasController)
|
|
38
|
+
application.register("toast", ToastController)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
ESBuildやViteなどを利用している場合も、同様にコントローラをインポートして登録してください。
|
|
42
|
+
|
|
43
|
+
### トースト用コンテナの設置
|
|
44
|
+
|
|
45
|
+
レイアウトなど、常に描画されるテンプレートに以下を追加しておくと、Turbo Stream経由でトーストを流し込めます。
|
|
46
|
+
|
|
47
|
+
```erb
|
|
48
|
+
<%= render_toast %>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
フラッシュメッセージを初期表示したい場合は `render_toast(flash_messages: flash)` のように渡してください。
|
|
52
|
+
|
|
53
|
+
## ビューヘルパー
|
|
54
|
+
|
|
55
|
+
### render_modal
|
|
56
|
+
|
|
57
|
+
Stripeダッシュボード風のモーダルDSLです。`render_modal` にIDとタイトルを渡し、ブロックで本文・フッターを組み立てます。
|
|
58
|
+
|
|
59
|
+
```erb
|
|
60
|
+
<%= render_modal id: "settingsModal", title: "設定", dialog: { size: :lg, centered: true } do |modal| %>
|
|
61
|
+
<% modal.body do %>
|
|
62
|
+
<turbo-frame id="modal-settings-frame">
|
|
63
|
+
<div class="text-center text-muted py-4">読み込み中...</div>
|
|
64
|
+
</turbo-frame>
|
|
65
|
+
<% end %>
|
|
66
|
+
<% end %>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
フォームを扱う場合は `form:` に `form_with` のオプションをそのまま渡してください。`modal.body` / `modal.footer` のブロックにはフォームビルダーが渡されます。
|
|
70
|
+
|
|
71
|
+
```erb
|
|
72
|
+
<%= render_modal id: "userModal", title: "ユーザー追加", form: { model: User.new, url: users_path } do |modal| %>
|
|
73
|
+
<% modal.body do |f| %>
|
|
74
|
+
<%= f.text_field :name, class: "form-control" %>
|
|
75
|
+
<% end %>
|
|
76
|
+
<% modal.footer do |f| %>
|
|
77
|
+
<%= f.submit "保存", class: "btn btn-primary" %>
|
|
78
|
+
<% end %>
|
|
79
|
+
<% end %>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
モーダルを開くトリガー要素には、Stimulusコントローラが参照する属性を付与します。
|
|
83
|
+
|
|
84
|
+
```erb
|
|
85
|
+
<%= link_to settings_path,
|
|
86
|
+
class: "btn btn-primary btn-sm",
|
|
87
|
+
data: { modal_target: "#settingsModal", turbo_frame: "modal-settings-frame" } do %>
|
|
88
|
+
設定を開く
|
|
89
|
+
<% end %>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
主なオプションです。
|
|
93
|
+
|
|
94
|
+
- `dialog: { size: :sm|:lg|:xl|:fullscreen, centered: true, scrollable: true }`
|
|
95
|
+
- `form:` `form_with` に渡すHash。指定時はブロックにフォームビルダーが渡されます。
|
|
96
|
+
- `data:` モーダル要素に付与するdata属性(`controller: "modal"` は自動付与されます)。
|
|
97
|
+
|
|
98
|
+
### render_offcanvas
|
|
99
|
+
|
|
100
|
+
Bootstrap 5.3のオフキャンバスをDSLで構築します。タイトルは第1引数またはキーワード引数で指定できます。
|
|
101
|
+
|
|
102
|
+
```erb
|
|
103
|
+
<%= render_offcanvas id: "previewOffcanvas", title: "プレビュー", placement: :end do %>
|
|
104
|
+
<turbo-frame id="offcanvas-form-template-preview">
|
|
105
|
+
読み込み中...
|
|
106
|
+
</turbo-frame>
|
|
107
|
+
<% end %>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
トリガー例:
|
|
111
|
+
|
|
112
|
+
```erb
|
|
113
|
+
<%= link_to preview_path,
|
|
114
|
+
class: "btn btn-outline-primary btn-sm",
|
|
115
|
+
data: { offcanvas_target: "#previewOffcanvas", turbo_frame: "offcanvas-form-template-preview" } do %>
|
|
116
|
+
プレビュー
|
|
117
|
+
<% end %>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- `placement:` は `:start|:end|:top|:bottom` を受け付けます(既定は`:end`)。
|
|
121
|
+
- `footer:` に文字列またはブロックを渡すと、フッター領域を描画します。
|
|
122
|
+
- `data:` で追加のdata属性を渡せます(`controller: "offcanvas"` を自動付与します)。
|
|
123
|
+
|
|
124
|
+
### render_card
|
|
125
|
+
|
|
126
|
+
カードを簡潔に定義できるDSLです。ヘッダー、本文、フッターを1度ずつ定義できます。
|
|
127
|
+
|
|
128
|
+
```erb
|
|
129
|
+
<%= render_card class: "mb-4" do |card| %>
|
|
130
|
+
<% card.header class: "d-flex align-items-center" do %>
|
|
131
|
+
設定
|
|
132
|
+
<% end %>
|
|
133
|
+
<% card.body class: "p-4" do %>
|
|
134
|
+
本文...
|
|
135
|
+
<% end %>
|
|
136
|
+
<% card.footer class: "text-end" do %>
|
|
137
|
+
<%= link_to "閉じる", "#", class: "btn btn-outline-secondary" %>
|
|
138
|
+
<% end %>
|
|
139
|
+
<% end %>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`data:` オプションで親要素にdata属性を追加できます。
|
|
143
|
+
|
|
144
|
+
### render_table
|
|
145
|
+
|
|
146
|
+
`table-responsive` ラッパー付きでBootstrapのテーブルを出力します。
|
|
147
|
+
|
|
148
|
+
```erb
|
|
149
|
+
<%= render_table class: "table-striped" do |table| %>
|
|
150
|
+
<% table.thead class: "table-light" do %>
|
|
151
|
+
<tr><th>名前</th><th>状態</th></tr>
|
|
152
|
+
<% end %>
|
|
153
|
+
<% table.tbody do %>
|
|
154
|
+
<% @users.each do |user| %>
|
|
155
|
+
<tr>
|
|
156
|
+
<td><%= user.name %></td>
|
|
157
|
+
<td><%= user.status %></td>
|
|
158
|
+
</tr>
|
|
159
|
+
<% end %>
|
|
160
|
+
<% end %>
|
|
161
|
+
<% end %>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`wrapper_class` や `wrapper_html` を渡すことでラッパー要素のカスタマイズも可能です。
|
|
165
|
+
|
|
166
|
+
### render_toast
|
|
167
|
+
|
|
168
|
+
トーストコンテナを描画し、フラッシュメッセージを初期表示できます。
|
|
169
|
+
|
|
170
|
+
```erb
|
|
171
|
+
<%= render_toast id: "toast-root", position: "top-0 end-0", flash_messages: flash %>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`position:` にはBootstrapのユーティリティクラスをそのまま渡してください。
|
|
175
|
+
|
|
176
|
+
## Turbo Streams拡張
|
|
177
|
+
|
|
178
|
+
`Turbo::Streams::TagBuilder` を拡張し、`turbo_stream.toast` を利用できるようにしています。トーストコンテナ(既定ID: `toast-root`)にメッセージを積み上げます。
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
# コントローラまたはビュー
|
|
182
|
+
render turbo_stream: turbo_stream.toast(:notice, "保存しました")
|
|
183
|
+
|
|
184
|
+
# 追加オプション
|
|
185
|
+
render turbo_stream: turbo_stream.toast(:alert, @user, target: "custom-toast", autohide: false, delay: 8000)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`message_or_record` にActiveModelを渡すと、エラー内容をリスト表示します。
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
ご不明点があればIssueやPull Requestでお気軽にお知らせください。
|
data/Rakefile
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bootstrap5RailsExtensions
|
|
4
|
+
module CardHelper
|
|
5
|
+
# Bootstrapのcardコンポーネントを簡潔に記述できるDSL。
|
|
6
|
+
#
|
|
7
|
+
# 使い方:
|
|
8
|
+
# <%= render_card class: "mb-4" do |card| %>
|
|
9
|
+
# <% card.header class: "d-flex align-items-center" do %>
|
|
10
|
+
# タイトル
|
|
11
|
+
# <% end %>
|
|
12
|
+
# <% card.body class: "p-4" do %>
|
|
13
|
+
# 本文...
|
|
14
|
+
# <% end %>
|
|
15
|
+
# <% card.footer class: "text-end" do %>
|
|
16
|
+
# フッター
|
|
17
|
+
# <% end %>
|
|
18
|
+
# <% end %>
|
|
19
|
+
#
|
|
20
|
+
# オプション:
|
|
21
|
+
# class: 親要素に追加するクラス
|
|
22
|
+
# data: 親要素に付与するdata属性
|
|
23
|
+
def render_card(data: {}, **html_options)
|
|
24
|
+
raise ArgumentError, "カードは本文を定義する必要があります" unless block_given?
|
|
25
|
+
|
|
26
|
+
builder = CardBuilder.new(self)
|
|
27
|
+
yield(builder)
|
|
28
|
+
|
|
29
|
+
html_options[:class] = class_names("card", html_options[:class])
|
|
30
|
+
|
|
31
|
+
if data.present?
|
|
32
|
+
html_options[:data] = (html_options[:data] || {}).merge(data)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
content_tag(:div, **html_options) do
|
|
36
|
+
builder.render
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class CardBuilder
|
|
41
|
+
def initialize(view_context)
|
|
42
|
+
@view = view_context
|
|
43
|
+
@header_html = nil
|
|
44
|
+
@header_options = {}
|
|
45
|
+
@body_fragments = []
|
|
46
|
+
@body_options = {}
|
|
47
|
+
@footer_html = nil
|
|
48
|
+
@footer_options = {}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def header(content = nil, **options, &block)
|
|
52
|
+
raise ArgumentError, "カードヘッダーは一度だけ定義できます" if @header_html
|
|
53
|
+
|
|
54
|
+
@header_html = extract_content(content, &block)
|
|
55
|
+
css_class = extract_css_class!(options)
|
|
56
|
+
@header_options[:class] = css_class if css_class.present?
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def body(content = nil, **options, &block)
|
|
61
|
+
html = extract_content(content, &block)
|
|
62
|
+
raise ArgumentError, "カード本文が空です" if blank_html?(html)
|
|
63
|
+
|
|
64
|
+
@body_fragments << html
|
|
65
|
+
css_class = extract_css_class!(options)
|
|
66
|
+
if css_class.present?
|
|
67
|
+
if @body_options[:class].present? && @body_options[:class] != css_class
|
|
68
|
+
raise ArgumentError, "カード本文のクラス指定は一度だけ行ってください"
|
|
69
|
+
end
|
|
70
|
+
@body_options[:class] = css_class
|
|
71
|
+
end
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def footer(content = nil, **options, &block)
|
|
76
|
+
raise ArgumentError, "カードフッターは一度だけ定義できます" if @footer_html
|
|
77
|
+
|
|
78
|
+
html = extract_content(content, &block)
|
|
79
|
+
@footer_html = html unless blank_html?(html)
|
|
80
|
+
css_class = extract_css_class!(options)
|
|
81
|
+
@footer_options[:class] = css_class if css_class.present?
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def render
|
|
86
|
+
raise ArgumentError, "カード本文を定義してください" if @body_fragments.empty?
|
|
87
|
+
|
|
88
|
+
fragments = []
|
|
89
|
+
fragments << wrap_section(@header_html, default_header_class, @header_options[:class]) if @header_html
|
|
90
|
+
fragments << wrap_section(@view.safe_join(@body_fragments), default_body_class, @body_options[:class])
|
|
91
|
+
fragments << wrap_section(@footer_html, default_footer_class, @footer_options[:class]) if @footer_html
|
|
92
|
+
@view.safe_join(fragments.compact)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def extract_content(content, &block)
|
|
98
|
+
if block_given?
|
|
99
|
+
@view.capture(&block)
|
|
100
|
+
else
|
|
101
|
+
content
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def extract_css_class!(options)
|
|
106
|
+
return nil if options.nil? || options.empty?
|
|
107
|
+
|
|
108
|
+
css_class = options.delete(:class)
|
|
109
|
+
raise ArgumentError, "サポートされていないオプションです: #{options.keys.join(', ')}" if options.present?
|
|
110
|
+
|
|
111
|
+
css_class
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def wrap_section(content, wrapper_class, extra_class = nil)
|
|
115
|
+
return if blank_html?(content)
|
|
116
|
+
if wrapper_class == false && extra_class.blank?
|
|
117
|
+
return content
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
combined_class = [wrapper_class == false ? nil : wrapper_class, extra_class.presence].compact.join(" ")
|
|
121
|
+
return content if combined_class.blank?
|
|
122
|
+
|
|
123
|
+
@view.content_tag(:div, content, class: combined_class)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def default_header_class
|
|
127
|
+
"card-header"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def default_body_class
|
|
131
|
+
"card-body"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def default_footer_class
|
|
135
|
+
"card-footer"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def blank_html?(html)
|
|
139
|
+
html.respond_to?(:blank?) ? html.blank? : html.to_s.strip.empty?
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|