bullet_train-themes-tailwind_css 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/config/bullet_train_themes_tailwind_css_manifest.js +0 -0
- data/app/views/themes/tailwind_css/attributes/_attempt.html.erb +24 -0
- data/app/views/themes/tailwind_css/fields/_buttons.html.erb +35 -0
- data/app/views/themes/tailwind_css/fields/_cloudinary_image.html.erb +61 -0
- data/app/views/themes/tailwind_css/fields/_color_picker.html.erb +48 -0
- data/app/views/themes/tailwind_css/fields/_date_and_time_field.html.erb +49 -0
- data/app/views/themes/tailwind_css/fields/_date_field.html.erb +31 -0
- data/app/views/themes/tailwind_css/fields/_field.html.erb +79 -0
- data/app/views/themes/tailwind_css/fields/_file_field.html.erb +39 -0
- data/app/views/themes/tailwind_css/fields/_options.html.erb +45 -0
- data/config/routes.rb +2 -0
- data/lib/bullet_train/themes/tailwind_css/engine.rb +10 -0
- data/lib/bullet_train/themes/tailwind_css/path_snitch.rb +9 -0
- data/lib/bullet_train/themes/tailwind_css/version.rb +7 -0
- data/lib/bullet_train/themes/tailwind_css.rb +10 -0
- data/lib/tasks/bullet_train/themes/tailwind_css_tasks.rake +4 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5c566ea84afbb658c67d730da4e7bd56d7974b43054cec8315627b8b0347c73c
|
4
|
+
data.tar.gz: 95f4456fe0f50644eed4664d861950e1517d9e0b373de71f26f3977b7d1a6d3d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 03b7499166adc33e60b5feb21cc92db6c2620ccec6a6dd916702e360db56172d7f37574b9b575257cd06307cff4d39e0a016b967e15d56990183363ecfdfd1ef
|
7
|
+
data.tar.gz: d2f7740e557dc8f3174bfbc1d37098fb18311b934128ca2b7c3d1566a6258e7448d64b31e349732364be98ed26796c79642c36d897e7c90837d10a45832565d8
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2022 Andrew Culver
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# BulletTrain::Themes::TailwindCss
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem "bullet_train-themes-tailwind_css"
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install bullet_train-themes-tailwind_css
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
File without changes
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<% object ||= current_attributes_object %>
|
2
|
+
<% strategy ||= current_attributes_strategy || :none %>
|
3
|
+
<% url ||= nil %>
|
4
|
+
|
5
|
+
<%= render 'shared/attributes/attribute', attribute: attribute, strategy: strategy, url: url do %>
|
6
|
+
<span class="inline-block">
|
7
|
+
<% if object.send(success_method) %>
|
8
|
+
<i class="fal fa-check ti ti-check text-green"></i>
|
9
|
+
<% elsif object.send(attempting_method) %>
|
10
|
+
<style>
|
11
|
+
<% if font_awesome? %>
|
12
|
+
@keyframes spinner { 100% { transform:rotate(360deg); } };
|
13
|
+
<% else %>
|
14
|
+
@keyframes spinner { 100% { transform:rotate(-360deg); } };
|
15
|
+
<% end %>
|
16
|
+
</style>
|
17
|
+
<span class="inline-block" style="animation: spinner 4s linear infinite;">
|
18
|
+
<i class="fal fa-sync ti ti-reload"></i>
|
19
|
+
</span>
|
20
|
+
<% elsif object.send(failure_method) %>
|
21
|
+
<i class="fal fa-close ti ti-close text-red"></i>
|
22
|
+
<% end %>
|
23
|
+
</span>
|
24
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
stimulus_controller = 'fields--button-toggle'
|
5
|
+
|
6
|
+
form ||= current_fields_form
|
7
|
+
html_options ||= {}
|
8
|
+
html_options[:id] ||= id_for(form, method)
|
9
|
+
multiple ||= false
|
10
|
+
other_options ||= {}
|
11
|
+
options ||= options_for(form, method)
|
12
|
+
%>
|
13
|
+
|
14
|
+
<% content = render 'shared/fields/field', form: form, method: method, options: html_options, other_options: other_options do %>
|
15
|
+
<% content_for :field do %>
|
16
|
+
<div>
|
17
|
+
<% options.each do |value, label| %>
|
18
|
+
<% checked = form.object.send(method).is_a?(Array) ? form.object.send(method).map(&:to_s).include?(value.to_s) : form.object.send(method).to_s == value.to_s %>
|
19
|
+
<label class="btn-toggle" data-controller="<%= stimulus_controller %>">
|
20
|
+
<% if multiple %>
|
21
|
+
<%= form.check_box method, {multiple: multiple, checked: checked, data: { "#{stimulus_controller}-target": 'shadowField' }}, value, "" %>
|
22
|
+
<% else %>
|
23
|
+
<%= form.radio_button method, value, { data: { "#{stimulus_controller}-target": 'shadowField' }, checked: checked} %>
|
24
|
+
<% end %>
|
25
|
+
<button type="button" class="button-alternative mb-1.5 mr-1" data-action="<%= stimulus_controller %>#clickShadowField">
|
26
|
+
<%= label %>
|
27
|
+
</button>
|
28
|
+
</label>
|
29
|
+
<% end %>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
33
|
+
|
34
|
+
<%# The `-mb-1.5` is making up for the `mb-1.5` on each of the buttons. This allows them to wrap with appropriate vertical spacing. %>
|
35
|
+
<div class="-mb-1.5"><%= content %></div>
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<% if cloudinary_enabled? %>
|
4
|
+
|
5
|
+
<%
|
6
|
+
stimulus_controller = 'fields--cloudinary-image'
|
7
|
+
|
8
|
+
form ||= current_fields_form
|
9
|
+
options ||= {}
|
10
|
+
options[:id] ||= id_for(form, method)
|
11
|
+
options[:width] ||= 100
|
12
|
+
options[:height] ||= 100
|
13
|
+
options[:cloud_name] ||= Cloudinary.config.cloud_name
|
14
|
+
options[:api_key] ||= Cloudinary.config.api_key
|
15
|
+
options[:google_search_key] ||= ENV['CLOUDINARY_GOOGLE_API_KEY']
|
16
|
+
other_options ||= {}
|
17
|
+
%>
|
18
|
+
|
19
|
+
<%
|
20
|
+
cloudinary_id = if_present(form.object.send(method))
|
21
|
+
preview_image_options = {width: options[:width]&.*(2), height: options[:height]&.*(2), crop: :fill}
|
22
|
+
cloudinary_url = cl_image_path(cloudinary_id, preview_image_options) if cloudinary_id
|
23
|
+
cloudinary_url_format = cl_image_path('CLOUDINARY_ID', preview_image_options)
|
24
|
+
%>
|
25
|
+
|
26
|
+
<%
|
27
|
+
thumbnail_shown_class = 'present'
|
28
|
+
wrapper_options = { data: {
|
29
|
+
controller: stimulus_controller,
|
30
|
+
"#{stimulus_controller}-signatures-url-value": new_account_cloudinary_upload_signature_path,
|
31
|
+
"#{stimulus_controller}-height-value": options[:height],
|
32
|
+
"#{stimulus_controller}-width-value": options[:width],
|
33
|
+
"#{stimulus_controller}-cloud-name-value": options[:cloud_name],
|
34
|
+
"#{stimulus_controller}-api-key-value": options[:api_key],
|
35
|
+
"#{stimulus_controller}-upload-preset-value": options[:upload_preset],
|
36
|
+
"#{stimulus_controller}-url-format-value": cloudinary_url_format,
|
37
|
+
"#{stimulus_controller}-thumbnail-shown-class": thumbnail_shown_class,
|
38
|
+
}}
|
39
|
+
wrapper_options[:data]["#{stimulus_controller}-google-api-key-value"] = options[:google_search_key] unless options[:google_search_key].blank?
|
40
|
+
%>
|
41
|
+
|
42
|
+
|
43
|
+
<%= render 'shared/fields/field', form: form, method: method, options: options, other_options: other_options do %>
|
44
|
+
<% content_for :field do %>
|
45
|
+
<%= content_tag :div, class: 'cloudinary-field', data: wrapper_options[:data] do %>
|
46
|
+
<%= form.hidden_field method, data: { "#{stimulus_controller}-target": 'hiddenField' } %>
|
47
|
+
<button type="button" class="upload <%= thumbnail_shown_class if cloudinary_url %>"
|
48
|
+
data-<%= stimulus_controller %>-target="uploadButton"
|
49
|
+
data-action="<%= stimulus_controller %>#pickImageAndUpload"
|
50
|
+
>
|
51
|
+
<%= image_tag cloudinary_url, width: options[:width], height: options[:height], data: { "#{stimulus_controller}-target": 'thumbnail' } if cloudinary_url %>
|
52
|
+
<i class="ti ti-cloud-up"></i>
|
53
|
+
</button>
|
54
|
+
<button type="button" class="clear" data-action="<%= stimulus_controller %>#clearImage">
|
55
|
+
<i class="ti ti-trash"></i>
|
56
|
+
</button>
|
57
|
+
<% end %>
|
58
|
+
<% end %>
|
59
|
+
<% end %>
|
60
|
+
|
61
|
+
<% end %>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
stimulus_controller = 'fields--color-picker'
|
5
|
+
|
6
|
+
form ||= current_fields_form
|
7
|
+
html_options ||= {}
|
8
|
+
html_options[:id] ||= id_for(form, method)
|
9
|
+
multiple ||= false
|
10
|
+
other_options ||= {}
|
11
|
+
options ||= options_for(form, method)
|
12
|
+
value = form.object.color_picker_value
|
13
|
+
%>
|
14
|
+
|
15
|
+
<% content = render 'shared/fields/field', form: form, method: method, options: html_options, other_options: other_options do %>
|
16
|
+
<% content_for :field do %>
|
17
|
+
<div class="space-x-1" data-controller="<%= stimulus_controller %>" data-<%= stimulus_controller %>-initial-color-value="<%= form.object.color_picker_value %>">
|
18
|
+
<%= form.hidden_field method, value: value, data: {"#{stimulus_controller}-target": "colorPickerValue"} %>
|
19
|
+
<div class="inline space-x-1" data-<%= stimulus_controller %>-target="colorOptions">
|
20
|
+
<% options.each do |color| %>
|
21
|
+
<label class="btn-toggle btn-color-picker">
|
22
|
+
<button type="button" class="button-color mb-1.5 dark:ring-offset-sealBlue-400 <%= color == value ? 'ring-2 ring-offset-2' : '' %>" style="background-color: <%= color %>; --tw-ring-color: <%= color %>" data-action="<%= stimulus_controller %>#pickColor" data-color="<%= color %>"> </button>
|
23
|
+
</label>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
<label class="btn-toggle btn-color-picker">
|
27
|
+
<button type="button" class="button-color mr-1 dark:ring-offset-sealBlue-400 <%= value.blank? || options.include?(value) ? 'hidden' : 'ring-2 ring-offset-2' %>" data-action="<%= stimulus_controller %>#pickColor" data-<%= stimulus_controller %>-target="userSelectedColor" data-color="<%= value %>" style="background-color: <%= value %>; --tw-ring-color: <%= value %>"> </button>
|
28
|
+
</label>
|
29
|
+
<span class="relative">
|
30
|
+
<input type="text" disabled="disabled" class="rounded-md shadow-sm font-light font-mono text-sm focus:ring-blue focus:border-blue border-gray-300 w-48 dark:bg-sealBlue-300 dark:border-sealBlue-100" value="<%= value %>" data-<%= stimulus_controller %>-target="colorInput"/>
|
31
|
+
<span class="absolute right-0">
|
32
|
+
<button type="button" class="py-2 px-1 border border-transparent inline-flex items-center whitespace-nowrap rounded-md text-lg" data-action="<%= stimulus_controller %>#pickRandomColor">
|
33
|
+
<i class="leading-5 ti ti-reload dark:text-blue-500"></i>
|
34
|
+
</button>
|
35
|
+
<button type="button" class="py-2 px-1 border border-transparent inline-flex items-center whitespace-nowrap rounded-md btn-pickr text-lg" data-action="<%= stimulus_controller %>#togglePickr">
|
36
|
+
<i class="leading-5 ti ti-pencil dark:text-blue-500"></i>
|
37
|
+
</button>
|
38
|
+
<button type="button" class="py-2 px-1 pr-3.5 border border-transparent inline-flex items-center whitespace-nowrap rounded-md text-lg" data-action="<%= stimulus_controller %>#unpickColor">
|
39
|
+
<i class="leading-5 ti ti-trash dark:text-blue-500"></i>
|
40
|
+
</button>
|
41
|
+
</span>
|
42
|
+
</span>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
45
|
+
<% end %>
|
46
|
+
|
47
|
+
<%# The `-mb-1` is making up for the `mb-1` on each of the buttons. This allows them to wrap with appropriate vertical spacing. %>
|
48
|
+
<div class="-mb-1.5"><%= content %></div>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
form ||= current_fields_form
|
5
|
+
options ||= {}
|
6
|
+
options[:id] ||= id_for(form, method)
|
7
|
+
options[:class] = "form-control single-daterange w-full dark:bg-sealBlue-300 dark:border-sealBlue-100 #{options[:class]}".strip
|
8
|
+
options[:value] = form.object.send(method)&.in_time_zone(current_team.time_zone)&.strftime(t('global.formats.date_and_time'))
|
9
|
+
options = options.merge({ data: {'fields--date-target': 'field' }})
|
10
|
+
other_options ||= {}
|
11
|
+
%>
|
12
|
+
|
13
|
+
<%= render 'shared/fields/field', form: form, method: method, options: options, other_options: other_options do %>
|
14
|
+
<% content_for :field do %>
|
15
|
+
<div class="date-input relative" data-controller="fields--date" data-fields--date-include-time-value="true" data-fields--date-default-time-zones-value="<%= "[\"#{current_user.current_team.time_zone}\",\"#{current_user.time_zone}\"]" %>">
|
16
|
+
<%= form.text_field method, options %>
|
17
|
+
<% unless options[:disabled] %>
|
18
|
+
<button type="button" class="clear py-2 px-3 border border-transparent inline-flex items-center whitespace-nowrap absolute rounded-md"
|
19
|
+
style="top: 2px; right: 2px;"
|
20
|
+
data-fields--date-target="clearButton"
|
21
|
+
data-action="fields--date#clearDate"
|
22
|
+
>
|
23
|
+
<i class="leading-4 text-lg ti ti-trash dark:text-blue-500"></i>
|
24
|
+
</button>
|
25
|
+
<% end %>
|
26
|
+
<% if current_user.time_zone != current_user.current_team.time_zone %>
|
27
|
+
<div class="mt-1.5 text-xs text-gray-500">
|
28
|
+
<%= form.hidden_field "#{method}_time_zone".to_sym, value: current_user.current_team.time_zone, data: {'fields--date-target': 'timeZoneField'} %>
|
29
|
+
<div data-fields--date-target="currentTimeZoneWrapper">
|
30
|
+
<%= link_to current_user.current_team.time_zone, '#', class: 'button-secondary p-0', data: {action: 'fields--date#showTimeZoneButtons'} %>
|
31
|
+
</div>
|
32
|
+
<div class="space-x-1 hidden" data-fields--date-target="timeZoneButtons">
|
33
|
+
<%= link_to '', '#', hidden: true, class: 'time-zone-button button-alternative button-smaller selected-option-time-zone-button hidden', data: {action: 'fields--date#setTimeZone', value: ''} %>
|
34
|
+
<%= link_to current_user.current_team.time_zone, '#', class: 'time-zone-button button button-smaller', data: {action: 'fields--date#setTimeZone', value: current_user.current_team.time_zone} %>
|
35
|
+
<%= link_to current_user.time_zone, '#', class: 'time-zone-button button-alternative button-smaller', data: {action: 'fields--date#setTimeZone', value: current_user.time_zone} %>
|
36
|
+
<%= link_to t('global.buttons.other'), '#', class: 'button-alternative button-smaller', data: {action: 'fields--date#showTimeZoneSelectWrapper'} %>
|
37
|
+
<%= link_to t('global.buttons.cancel'), '#', class: 'button-secondary button-smaller', data: {action: 'fields--date#resetTimeZoneUI'} %>
|
38
|
+
</div>
|
39
|
+
<div class="hidden flex flex-row items-center mt-3 text-sm" data-fields--date-target="timeZoneSelectWrapper">
|
40
|
+
<div class="flex-grow">
|
41
|
+
<%= select_tag :time_zone, options_from_collection_for_select(ActiveSupport::TimeZone.all, "name", "to_s", current_user.current_team.time_zone), {class: 'form-control select2'} %>
|
42
|
+
</div>
|
43
|
+
<%= link_to t('global.buttons.cancel'), '#', class: 'button-secondary ml-1.5', data: {action: 'fields--date#resetTimeZoneUI'} %>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
<% end %>
|
47
|
+
</div>
|
48
|
+
<% end %>
|
49
|
+
<% end %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
stimulus_controller = 'fields--date'
|
5
|
+
|
6
|
+
form ||= current_fields_form
|
7
|
+
options ||= {}
|
8
|
+
options[:id] ||= id_for(form, method)
|
9
|
+
options[:class] = "form-control single-daterange w-full border-gray-300 dark:bg-sealBlue-300 dark:border-sealBlue-100 #{options[:class]}".strip
|
10
|
+
options[:value] = form.object.send(method)&.strftime(t('global.formats.date'))
|
11
|
+
options = options.merge({ data: {"#{stimulus_controller}-target": 'field' }})
|
12
|
+
other_options ||= {}
|
13
|
+
|
14
|
+
%>
|
15
|
+
|
16
|
+
<%= render 'shared/fields/field', form: form, method: method, options: options, other_options: other_options do %>
|
17
|
+
<% content_for :field do %>
|
18
|
+
<div class="date-input relative" data-controller="<%= stimulus_controller %>">
|
19
|
+
<%= form.text_field method, options %>
|
20
|
+
<% unless options[:disabled] %>
|
21
|
+
<button type="button" class="clear py-2 px-3 border border-transparent inline-flex items-center whitespace-nowrap absolute rounded-md"
|
22
|
+
style="top: 2px; right: 2px;"
|
23
|
+
data-<%= stimulus_controller %>-target="clearButton"
|
24
|
+
data-action="<%= stimulus_controller %>#clearDate"
|
25
|
+
>
|
26
|
+
<i class="leading-4 text-lg ti ti-trash dark:text-blue-500"></i>
|
27
|
+
</button>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
@@ -0,0 +1,79 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
form ||= current_fields_form
|
5
|
+
# returns a struct with `label`, `placeholder`, and `help` methods.
|
6
|
+
labels = labels_for(form, method)
|
7
|
+
options ||= {}
|
8
|
+
options[:id] ||= id_for(form, method)
|
9
|
+
# options[:disabled] ||= !field_editable?(form.object, method) if user_signed_in?
|
10
|
+
options[:placeholder] ||= labels.placeholder if labels.placeholder
|
11
|
+
other_options ||= {}
|
12
|
+
other_options[:help] = [other_options[:help], labels.help].compact.join(" ")
|
13
|
+
|
14
|
+
errors = [method, method.to_s.gsub(/_id$/, '').to_sym].uniq.map { |attribute| form.object.errors.full_messages_for(attribute) }.flatten
|
15
|
+
has_errors = errors.any? || content_for(:error).present? || other_options[:error].present?
|
16
|
+
|
17
|
+
options[:class] = "#{options[:class]} block w-full rounded-md shadow-sm font-light text-sm"
|
18
|
+
|
19
|
+
options[:class] += if has_errors
|
20
|
+
" pr-10 border-red text-red-darker placeholder-red focus:outline-none focus:ring-red focus:border-red"
|
21
|
+
else
|
22
|
+
" focus:ring-blue focus:border-blue border-gray-300"
|
23
|
+
end
|
24
|
+
|
25
|
+
%>
|
26
|
+
|
27
|
+
<div class="<%= 'required' if presence_validated?(form.object, method) %>">
|
28
|
+
|
29
|
+
<% # the label. %>
|
30
|
+
<% unless other_options[:hide_label] == true %>
|
31
|
+
<% if content_for? :label %>
|
32
|
+
<%= yield :label %>
|
33
|
+
<% flush_content_for :label %>
|
34
|
+
<% else %>
|
35
|
+
<% # allow the label to be defined via an inline option or else one of the locale yaml definitions. %>
|
36
|
+
<% label = (other_options[:label].presence || labels.label || legacy_label_for(form, method)) %>
|
37
|
+
<%= form.label method, label&.html_safe, class: 'block', for: options[:id] %>
|
38
|
+
<% end %>
|
39
|
+
<% end %>
|
40
|
+
|
41
|
+
<div class="mt-1.5">
|
42
|
+
|
43
|
+
<% # the actual field. %>
|
44
|
+
<% if content_for? :field %>
|
45
|
+
<%= yield :field %>
|
46
|
+
<% flush_content_for :field %>
|
47
|
+
<% else %>
|
48
|
+
<% # e.g. form.text_field(method, options) %>
|
49
|
+
<%= form.send(helper, method, options) %>
|
50
|
+
<% end %>
|
51
|
+
|
52
|
+
</div>
|
53
|
+
|
54
|
+
<% # any error messages. %>
|
55
|
+
<% if has_errors %>
|
56
|
+
<p class="mt-1.5 text-xs text-red">
|
57
|
+
<%= errors.map { |error| error + ". " }.join %>
|
58
|
+
<%= yield :error %>
|
59
|
+
<% flush_content_for :error %>
|
60
|
+
<%= other_options[:error]&.html_safe %>
|
61
|
+
</p>
|
62
|
+
<% end %>
|
63
|
+
|
64
|
+
<% # any help text. %>
|
65
|
+
<% if content_for?(:help) || other_options[:help] || content_for?(:after_help) %>
|
66
|
+
<p class="mt-1.5 text-xs text-gray-500">
|
67
|
+
<%= yield :help %>
|
68
|
+
<% flush_content_for :help %>
|
69
|
+
<%= other_options[:help]&.html_safe %>
|
70
|
+
<%= yield :after_help %>
|
71
|
+
<% flush_content_for :after_help %>
|
72
|
+
</p>
|
73
|
+
<% end %>
|
74
|
+
|
75
|
+
<% if other_options[:icon] %>
|
76
|
+
<div class="pre-icon os-icon <%= other_options[:icon] %>"></div>
|
77
|
+
<% end %>
|
78
|
+
|
79
|
+
</div>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
form ||= current_fields_form
|
5
|
+
options ||= {}
|
6
|
+
other_options ||= {}
|
7
|
+
%>
|
8
|
+
|
9
|
+
<%= render 'shared/fields/field', form: form, method: method, helper: :file_field, options: options, other_options: other_options do %>
|
10
|
+
<% content_for :field do %>
|
11
|
+
<div class="file-field" data-controller="fields--file-field">
|
12
|
+
<%= form.hidden_field "#{method}_removal".to_sym, value: nil, data: {'fields--file-field-target': 'removeFileFlag'} %>
|
13
|
+
<%= form.file_field method, class: 'file-upload hidden', direct_upload: true, data: {'fields--file-field-target': 'fileField', action: 'change->fields--file-field#handleFileSelected'} %>
|
14
|
+
<div>
|
15
|
+
<% if form.object.send(method).attached? %>
|
16
|
+
<%= link_to url_for(form.object.send(method)), class: 'button download-file mr-3', data: {'fields--file-field-target': 'downloadFileButton'} do %>
|
17
|
+
<i class="leading-none mr-2 text-base ti ti-download"></i>
|
18
|
+
<span>Download Current Document</span>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
21
|
+
<% if form.object.send(method).attached? %>
|
22
|
+
<div class="button-alternative cursor-pointer mr-3" data-action="click->fields--file-field#removeFile" data-fields--file-field-target="removeFileButton">
|
23
|
+
<i class="leading-none mr-2 text-base ti ti-trash"></i>
|
24
|
+
<span>Remove Current Document</span>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
28
|
+
<div class="mt-2">
|
29
|
+
<div class="button-alternative cursor-pointer" data-action="click->fields--file-field#uploadFile" data-fields--file-field-target="selectFileButton">
|
30
|
+
<i class="leading-none mr-2 text-base ti ti-upload dark:text-white"></i>
|
31
|
+
<span class="dark:text-white">Upload New Document</span>
|
32
|
+
</div>
|
33
|
+
<div class="mt-2 hidden flex overflow-hidden text-xs rounded bg-black-400">
|
34
|
+
<div data-fields--file-field-target="progressBar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" class="flex flex-col justify-center text-white text-center whitespace-nowrap overflow-hidden bg-sealBlue-300" role="progressbar" style="width: 0%;"> 0%</div>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
<% end %>
|
39
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<% yield %>
|
2
|
+
|
3
|
+
<%
|
4
|
+
form ||= current_fields_form
|
5
|
+
html_options ||= {}
|
6
|
+
html_options[:id] ||= id_for(form, method)
|
7
|
+
multiple ||= false
|
8
|
+
other_options ||= {}
|
9
|
+
options ||= options_for(form, method)
|
10
|
+
labels = labels_for(form, method)
|
11
|
+
%>
|
12
|
+
|
13
|
+
<%= render 'shared/fields/field', form: form, method: method, options: html_options, other_options: other_options do %>
|
14
|
+
<% content_for :field do %>
|
15
|
+
<div class="pt-1.5 pb-1 sm:col-span-2">
|
16
|
+
<div class="max-w-lg space-y-3">
|
17
|
+
|
18
|
+
<% options.each do |value, label| %>
|
19
|
+
|
20
|
+
<label class="relative flex items-start">
|
21
|
+
<div class="flex items-center h-5">
|
22
|
+
|
23
|
+
<% if multiple %>
|
24
|
+
<%= form.check_box method, {multiple: multiple, checked: form.object.send(method).map(&:to_s).include?(value.to_s), class: "focus:ring-blue h-4 w-4 text-blue border-gray-300 rounded"}, value, "" %>
|
25
|
+
<% else %>
|
26
|
+
<%= form.radio_button method, value, {class: "focus:ring-blue h-4 w-4 text-blue border-gray-300"} %>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
</div>
|
30
|
+
<div class="ml-2.5 text-sm">
|
31
|
+
<div class="select-none"><%= label %></div>
|
32
|
+
<% if labels.options_help&.dig(value)&.present? %>
|
33
|
+
<p class="mt-0.5 text-xs text-gray-500">
|
34
|
+
<%= labels.options_help.dig(value) %>
|
35
|
+
</p>
|
36
|
+
<% end %>
|
37
|
+
</div>
|
38
|
+
</label>
|
39
|
+
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
45
|
+
<% end %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# TODO This is my best attempt at allowing us to figure out where theme partials might be getting served from.
|
2
|
+
# We can only inspect the source location of a class (not a module), and this gem has no other classes, so we need this.
|
3
|
+
# See https://stackoverflow.com/questions/13012109/get-class-location-from-class-object for context.
|
4
|
+
class BulletTrain::Themes::TailwindCss::PathSnitch
|
5
|
+
def self.confess
|
6
|
+
# This method allows us to call `BulletTrain::Themes::PathSnitch.method(:confess).source_location` and see where
|
7
|
+
# this gem is being served from... which allows us to check it's `view/themes` directory for partials.
|
8
|
+
end
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bullet_train-themes-tailwind_css
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Culver
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.0
|
27
|
+
description: Bullet Train Themes Tailwind CSS Base
|
28
|
+
email:
|
29
|
+
- andrew.culver@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- MIT-LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- app/assets/config/bullet_train_themes_tailwind_css_manifest.js
|
38
|
+
- app/views/themes/tailwind_css/attributes/_attempt.html.erb
|
39
|
+
- app/views/themes/tailwind_css/fields/_buttons.html.erb
|
40
|
+
- app/views/themes/tailwind_css/fields/_cloudinary_image.html.erb
|
41
|
+
- app/views/themes/tailwind_css/fields/_color_picker.html.erb
|
42
|
+
- app/views/themes/tailwind_css/fields/_date_and_time_field.html.erb
|
43
|
+
- app/views/themes/tailwind_css/fields/_date_field.html.erb
|
44
|
+
- app/views/themes/tailwind_css/fields/_field.html.erb
|
45
|
+
- app/views/themes/tailwind_css/fields/_file_field.html.erb
|
46
|
+
- app/views/themes/tailwind_css/fields/_options.html.erb
|
47
|
+
- config/routes.rb
|
48
|
+
- lib/bullet_train/themes/tailwind_css.rb
|
49
|
+
- lib/bullet_train/themes/tailwind_css/engine.rb
|
50
|
+
- lib/bullet_train/themes/tailwind_css/path_snitch.rb
|
51
|
+
- lib/bullet_train/themes/tailwind_css/version.rb
|
52
|
+
- lib/tasks/bullet_train/themes/tailwind_css_tasks.rake
|
53
|
+
homepage: https://github.com/bullet-train-co/bullet_train-themes-tailwind_css
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata:
|
57
|
+
homepage_uri: https://github.com/bullet-train-co/bullet_train-themes-tailwind_css
|
58
|
+
source_code_uri: https://github.com/bullet-train-co/bullet_train-themes-tailwind_css
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubygems_version: 3.2.22
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Bullet Train Themes Tailwind CSS Base
|
78
|
+
test_files: []
|