bullet_train-themes-light 1.0.44 → 1.0.49
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/assets/stylesheets/light/application.css +1 -0
- data/app/assets/stylesheets/light/devise.css +15 -0
- data/app/assets/stylesheets/light/tailwind/dark-mode.css +12 -3
- data/app/views/themes/light/_alert.html.erb +1 -1
- data/app/views/themes/light/_box.html.erb +1 -1
- data/app/views/themes/light/fields/_field.html.erb +3 -3
- data/app/views/themes/light/layouts/_account.html.erb +13 -21
- data/app/views/themes/light/layouts/_devise.html.erb +1 -1
- data/lib/bullet_train/themes/light/custom_theme_file_replacer.rb +234 -0
- data/lib/bullet_train/themes/light/file_replacer.rb +18 -0
- data/lib/bullet_train/themes/light/version.rb +1 -1
- data/lib/bullet_train/themes/light.rb +3 -0
- data/lib/tasks/application.rb +180 -0
- data/lib/tasks/bullet_train/themes/light_tasks.rake +19 -44
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd88ca1040ba3794f38b71d0b9132c453d76635622c8e4d216ab755132eba8f1
|
4
|
+
data.tar.gz: b0e8112604cf0fcd6a838f75882678f87638cfac048d2ba060b19920e6a8a6d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 583e40b6889d5a5b054272420de74ccc542c1fb90bca4ae9cf043d79742e3c547f6dea3809cbf9c008364556fbf1b46108b997424ac3f9a62019a9284f77beee
|
7
|
+
data.tar.gz: 482181c6637700c2812270455e0cbee81c5acdefa1ba4c91dd28e0a144bec042a94168551cd831734586a79d102ac907960a8996b5b5f6041478cfdabcb9b6f3
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This takes care of the window's contents shifting when the
|
3
|
+
* scrollbar appears and disappears during the turn.css animation
|
4
|
+
*/
|
5
|
+
|
6
|
+
/* Chrome, Safari and Opera */
|
7
|
+
.devise_layout::-webkit-scrollbar {
|
8
|
+
display: none;
|
9
|
+
}
|
10
|
+
|
11
|
+
/* Firefox and Edge */
|
12
|
+
.devise_layout {
|
13
|
+
-ms-overflow-style: none;
|
14
|
+
scrollbar-width: none;
|
15
|
+
}
|
@@ -8,11 +8,10 @@
|
|
8
8
|
background-color: rgba(0, 0, 0, 0.15);
|
9
9
|
}
|
10
10
|
|
11
|
-
.bg-
|
11
|
+
.bg-light-gradient {
|
12
12
|
&:before {
|
13
13
|
background: linear-gradient(to bottom right, var(--dark-gradient-from), var(--dark-gradient-to) 100%);
|
14
14
|
}
|
15
|
-
background: linear-gradient(to bottom right, var(--dark-gradient-from), var(--dark-gradient-to) 100%);
|
16
15
|
}
|
17
16
|
|
18
17
|
/**
|
@@ -179,8 +178,18 @@
|
|
179
178
|
}
|
180
179
|
|
181
180
|
trix-toolbar {
|
181
|
+
@apply opacity-50 !important;
|
182
|
+
|
183
|
+
&.visible {
|
184
|
+
@apply opacity-100 !important;
|
185
|
+
}
|
186
|
+
|
182
187
|
.trix-button-group, .trix-button {
|
183
|
-
@apply border-darkPrimary-
|
188
|
+
@apply border-darkPrimary-400 !important;
|
189
|
+
}
|
190
|
+
|
191
|
+
.trix-button:disabled::before {
|
192
|
+
@apply opacity-25;
|
184
193
|
}
|
185
194
|
}
|
186
195
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% color ||= 'yellow' %>
|
2
2
|
|
3
3
|
<div class="rounded-md bg-<%= color %>-400 border border-<%= color %>-500 py-4 px-5 mb-3">
|
4
|
-
<h3 class="text-sm text
|
4
|
+
<h3 class="text-sm text-black-400 font-light">
|
5
5
|
<%= yield %>
|
6
6
|
</h3>
|
7
7
|
</div>
|
@@ -5,7 +5,7 @@ form ||= current_fields_form
|
|
5
5
|
# returns a struct with `label`, `placeholder`, and `help` methods.
|
6
6
|
labels = labels_for(form, method)
|
7
7
|
options ||= {}
|
8
|
-
options[:id] ||=
|
8
|
+
options[:id] ||= form.field_id(method)
|
9
9
|
# options[:disabled] ||= !field_editable?(form.object, method) if user_signed_in?
|
10
10
|
options[:placeholder] ||= labels.placeholder if labels.placeholder
|
11
11
|
other_options ||= {}
|
@@ -53,7 +53,7 @@ end
|
|
53
53
|
|
54
54
|
<% # any error messages. %>
|
55
55
|
<% if has_errors %>
|
56
|
-
<p class="mt-1.5 text-xs text-red
|
56
|
+
<p class="mt-1.5 text-xs text-red">
|
57
57
|
<%= errors.map { |error| error + ". " }.join %>
|
58
58
|
<%= yield :error %>
|
59
59
|
<% flush_content_for :error %>
|
@@ -64,7 +64,7 @@ end
|
|
64
64
|
<% end %>
|
65
65
|
|
66
66
|
<% # any help text. %>
|
67
|
-
<% if content_for?(:help) || other_options[:help] || content_for?(:after_help) %>
|
67
|
+
<% if content_for?(:help) || other_options[:help].present? || content_for?(:after_help) %>
|
68
68
|
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
69
69
|
<%= yield :help %>
|
70
70
|
<% flush_content_for :help %>
|
@@ -9,8 +9,6 @@
|
|
9
9
|
<div class="h-screen md:h-auto overflow-hidden md:rounded-lg flex shadow main-container"
|
10
10
|
data-controller="mobile-menu"
|
11
11
|
data-mobile-menu-hidden-class="hidden"
|
12
|
-
data-mobile-menu-show-event-name-value="mobile-menu:show"
|
13
|
-
data-mobile-menu-hide-event-name-value="mobile-menu:hide"
|
14
12
|
>
|
15
13
|
|
16
14
|
<% menu = capture do %>
|
@@ -19,7 +17,8 @@
|
|
19
17
|
|
20
18
|
<div class="lg:hidden absolute right-0">
|
21
19
|
<button class="ml-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white dark:ring-transparent"
|
22
|
-
|
20
|
+
id="mobile-menu-close"
|
21
|
+
data-action="mobile-menu#close"
|
23
22
|
>
|
24
23
|
<span class="sr-only">Close Application Menu</span>
|
25
24
|
<svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
@@ -56,20 +55,13 @@
|
|
56
55
|
|
57
56
|
<div class="lg:hidden hidden"
|
58
57
|
data-mobile-menu-target="wrapper"
|
59
|
-
|
60
|
-
data-controller="reveal"
|
61
|
-
data-reveal-away-value="true"
|
62
|
-
data-reveal-hide-keys-value="escape"
|
63
|
-
|
64
|
-
data-action="mobile-menu:show->reveal#show mobile-menu:hide->reveal#hide mobile-menu-toggle->reveal#toggle reveal:hidden->mobile-menu#hideWrapper"
|
58
|
+
id="mobile-menu-backdrop"
|
65
59
|
>
|
66
60
|
<div class="fixed inset-0 flex z-40">
|
67
61
|
<button
|
68
|
-
data-
|
69
|
-
|
70
|
-
|
71
|
-
data-reveal
|
72
|
-
data-transition
|
62
|
+
data-mobile-menu-target="revealable"
|
63
|
+
data-action="mobile-menu#close"
|
64
|
+
|
73
65
|
data-transition-enter="transition-opacity ease-linear duration-200"
|
74
66
|
data-transition-enter-start="opacity-0"
|
75
67
|
data-transition-enter-end="opacity-100"
|
@@ -77,14 +69,13 @@
|
|
77
69
|
data-transition-leave-start="opacity-100"
|
78
70
|
data-transition-leave-end="opacity-0"
|
79
71
|
|
80
|
-
class="fixed inset-0" aria-hidden="true"
|
72
|
+
class="hidden fixed inset-0" aria-hidden="true"
|
81
73
|
>
|
82
74
|
<div class="absolute inset-0 bg-light-gradient opacity-75"></div>
|
83
75
|
</button>
|
84
76
|
<div
|
85
|
-
|
86
|
-
|
87
|
-
data-transition
|
77
|
+
data-mobile-menu-target="revealable"
|
78
|
+
|
88
79
|
data-transition-enter="transition ease-in-out duration-200 transform"
|
89
80
|
data-transition-enter-start="-trandarkPrimary-x-full"
|
90
81
|
data-transition-enter-end="trandarkPrimary-x-0"
|
@@ -92,7 +83,7 @@
|
|
92
83
|
data-transition-leave-start="trandarkPrimary-x-0"
|
93
84
|
data-transition-leave-end="-trandarkPrimary-x-full"
|
94
85
|
|
95
|
-
class="relative flex-1 flex flex-col max-w-xs w-full pb-4 bg-
|
86
|
+
class="hidden relative flex-1 flex flex-col max-w-xs w-full pb-4 bg-darkPrimary-800 shadow-xl"
|
96
87
|
>
|
97
88
|
<%= menu %>
|
98
89
|
</div>
|
@@ -109,8 +100,9 @@
|
|
109
100
|
<div class="flex flex-col w-0 flex-1 overflow-y-auto bg-gray-100 dark:bg-darkPrimary-800 lg:border-l dark:border-gray-500">
|
110
101
|
<main class="flex-1 relative z-0 focus:outline-none" tabindex="0">
|
111
102
|
<div class="flex flex-row items-center shadow-sm electron-draggable">
|
112
|
-
<button class="
|
113
|
-
|
103
|
+
<button class="lg:hidden h-12 w-12 ml-1 flex-none inline-flex items-center justify-center rounded-md text-gray-500 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500"
|
104
|
+
id="mobile-menu-open"
|
105
|
+
data-action="mobile-menu#open"
|
114
106
|
>
|
115
107
|
<span class="sr-only">Open Application Menu</span>
|
116
108
|
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<head>
|
4
4
|
<%= render 'shared/layouts/head' %>
|
5
5
|
</head>
|
6
|
-
<body class="bg-light-gradient text-gray-700 text-sm font-normal electron-draggable dark:bg-dark-gradient dark:text-darkPrimary-300">
|
6
|
+
<body class="devise_layout bg-light-gradient text-gray-700 text-sm font-normal electron-draggable dark:bg-dark-gradient dark:text-darkPrimary-300">
|
7
7
|
<div data-turn-enter data-turn-exit>
|
8
8
|
<%= yield %>
|
9
9
|
</div>
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module BulletTrain
|
2
|
+
module Themes
|
3
|
+
module Light
|
4
|
+
class CustomThemeFileReplacer
|
5
|
+
mattr_accessor :repo_path
|
6
|
+
|
7
|
+
include BulletTrain::Themes::Light::FileReplacer
|
8
|
+
|
9
|
+
def initialize(custom_theme)
|
10
|
+
@repo_path = "./local/bullet_train-themes-#{custom_theme}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def replace_theme(original_theme, custom_theme)
|
14
|
+
# Rename the directories
|
15
|
+
[
|
16
|
+
"/app/assets/stylesheets/bullet_train/themes/#{original_theme}/",
|
17
|
+
"/app/assets/stylesheets/#{original_theme}/",
|
18
|
+
"/app/views/themes/#{original_theme}/",
|
19
|
+
"/lib/bullet_train/themes/#{original_theme}/"
|
20
|
+
].map { |file| @repo_path + file }.each do |original_directory|
|
21
|
+
custom_directory = original_directory.gsub(/(.*)(#{original_theme})(\/$)/, '\1' + custom_theme + '\3')
|
22
|
+
FileUtils.mv(original_directory, custom_directory)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Only compare ejected files.
|
26
|
+
files_to_replace =
|
27
|
+
ejected_files_to_replace(original_theme, custom_theme).map { |file| {file_name: file, must_compare: true} } +
|
28
|
+
default_files_to_replace(original_theme).map { |file| {file_name: file, must_compare: false} }
|
29
|
+
|
30
|
+
# Replace the file contents and rename the files.
|
31
|
+
files_to_replace.each do |custom_gem_file|
|
32
|
+
# All of the files we want to compare against the fresh gem are in the main app.
|
33
|
+
main_app_file = build_main_app_file_name(original_theme, custom_theme, custom_gem_file[:file_name].gsub(@repo_path, "."))
|
34
|
+
custom_gem_file[:file_name] = adjust_directory_hierarchy(custom_gem_file[:file_name], original_theme)
|
35
|
+
|
36
|
+
# The content in the main app should replace the cloned gem files.
|
37
|
+
begin
|
38
|
+
if custom_gem_file[:must_compare] && !BulletTrain::Themes::Light::FileReplacer.files_have_same_content?(custom_gem_file[:file_name], main_app_file)
|
39
|
+
BulletTrain::Themes::Light::FileReplacer.replace_content(old: custom_gem_file[:file_name], new: main_app_file)
|
40
|
+
end
|
41
|
+
rescue Errno::ENOENT => _
|
42
|
+
puts "Skipping \`#{main_app_file}\` because it isn't present."
|
43
|
+
end
|
44
|
+
|
45
|
+
# Only rename file names that still have the original theme in them, i.e. - ./tailwind.config.light.js
|
46
|
+
if File.basename(custom_gem_file[:file_name]).match?(original_theme)
|
47
|
+
main_app_file = adjust_directory_hierarchy(main_app_file, custom_theme)
|
48
|
+
new_file_name = main_app_file.gsub(/^\./, @repo_path).gsub(original_theme, custom_theme)
|
49
|
+
File.rename(custom_gem_file[:file_name], new_file_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Change the content of specific files that contain the orignal theme's string.
|
54
|
+
# i.e. - `module Light` and `tailwind.light.config`.
|
55
|
+
constantized_original = constantize_from_snake_case(original_theme)
|
56
|
+
constantized_custom = constantize_from_snake_case(custom_theme)
|
57
|
+
files_whose_contents_need_to_be_replaced(custom_theme).each do |file|
|
58
|
+
new_lines = []
|
59
|
+
File.open(file, "r") do |f|
|
60
|
+
new_lines = f.readlines
|
61
|
+
new_lines = new_lines.map do |line|
|
62
|
+
# We want the original theme it's being edited from when creating a new theme.
|
63
|
+
# We also remove mattr_accessor in the eject task, so we need to add it back here.
|
64
|
+
if f.path == "#{@repo_path}/lib/bullet_train/themes/#{custom_theme}.rb" && line.match?("class Theme < BulletTrain::Themes::")
|
65
|
+
line = " mattr_accessor :color, default: :blue\n class Theme < BulletTrain::Themes::#{constantize_from_snake_case(original_theme)}::Theme\n"
|
66
|
+
else
|
67
|
+
# `_account.html.erb` and `_devise.html.erb` have tailwind classes that contain `light`.
|
68
|
+
# We shouldn't be replacing the classes with the custom theme string, so we skip it here.
|
69
|
+
# TODO: We should change this Regexp to check if the original theme is prefixed with `-`.
|
70
|
+
# If it is, we ignore the string if it's not prefixed with `bullet_train-themes-`,
|
71
|
+
line.gsub!(original_theme, custom_theme) unless line.match?("bg-light-gradient")
|
72
|
+
line.gsub!(constantized_original, constantized_custom)
|
73
|
+
end
|
74
|
+
line
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
File.open(file, "w") do |f|
|
79
|
+
f.puts new_lines.join
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# The contents in this specific main app file don't have the require statements which the gem
|
84
|
+
# originally has, so we add those back after moving the main app file contents to the gem.
|
85
|
+
new_lines = nil
|
86
|
+
File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}.rb", "r") do |file|
|
87
|
+
new_lines = file.readlines
|
88
|
+
require_lines =
|
89
|
+
<<~RUBY
|
90
|
+
require "bullet_train/themes/#{custom_theme}/version"
|
91
|
+
require "bullet_train/themes/#{custom_theme}/engine"
|
92
|
+
require "bullet_train/themes/#{original_theme}"
|
93
|
+
|
94
|
+
RUBY
|
95
|
+
new_lines.unshift(require_lines)
|
96
|
+
end
|
97
|
+
File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}.rb", "w") do |file|
|
98
|
+
file.puts new_lines.flatten.join
|
99
|
+
end
|
100
|
+
|
101
|
+
# Since we're generating a new gem, it should be version 1.0
|
102
|
+
File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}/version.rb", "r") do |file|
|
103
|
+
new_lines = file.readlines
|
104
|
+
new_lines = new_lines.map { |line| line.match?("VERSION") ? " VERSION = \"1.0\"\n" : line }
|
105
|
+
end
|
106
|
+
File.open("#{@repo_path}/lib/bullet_train/themes/#{custom_theme}/version.rb", "w") do |file|
|
107
|
+
file.puts new_lines.join
|
108
|
+
end
|
109
|
+
|
110
|
+
# Remove files and directories from the main application.
|
111
|
+
files_to_remove_from_main_app(custom_theme).each { |file| File.delete(file) }
|
112
|
+
directories_to_remove_from_main_app(custom_theme).each do |directory|
|
113
|
+
FileUtils.rm_rf(directory) unless directory.nil?
|
114
|
+
end
|
115
|
+
|
116
|
+
# Update the author and email.
|
117
|
+
# If the developer hasn't set these yet, this should simply return empty strings.
|
118
|
+
author = `git config --global user.name`.chomp
|
119
|
+
email = `git config --global user.email`.chomp
|
120
|
+
File.open("#{@repo_path}/bullet_train-themes-#{custom_theme}.gemspec", "r") do |file|
|
121
|
+
new_lines = file.readlines
|
122
|
+
new_lines = new_lines.map do |line|
|
123
|
+
if line.match?("spec.authors")
|
124
|
+
" spec.authors = [\"#{author}\"]\n"
|
125
|
+
elsif line.match?("spec.email")
|
126
|
+
" spec.email = [\"#{email}\"]\n"
|
127
|
+
else
|
128
|
+
line
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
File.open("#{@repo_path}/bullet_train-themes-#{custom_theme}.gemspec", "w") do |file|
|
133
|
+
file.puts new_lines.join
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# By the time we call this method we have already updated the new gem's directories with
|
138
|
+
# the custom theme name, but the FILE names are still the same from when they were cloned,
|
139
|
+
# so we use `original_theme` for specific file names below.
|
140
|
+
def ejected_files_to_replace(original_theme, custom_theme)
|
141
|
+
[
|
142
|
+
Dir.glob("#{@repo_path}/app/assets/stylesheets/#{custom_theme}/**/*.css"),
|
143
|
+
Dir.glob("#{@repo_path}/app/assets/stylesheets/#{custom_theme}/**/*.scss"),
|
144
|
+
Dir.glob("#{@repo_path}/app/views/themes/#{custom_theme}/**/*.html.erb"),
|
145
|
+
"/app/javascript/application.#{original_theme}.js",
|
146
|
+
"/tailwind.#{original_theme}.config.js",
|
147
|
+
"/app/lib/bullet_train/themes/#{original_theme}.rb",
|
148
|
+
# The Glob up top doesn't grab the #{original_theme}.tailwind.css file, so we set that here.
|
149
|
+
"/app/assets/stylesheets/#{original_theme}.tailwind.css",
|
150
|
+
"/tailwind.mailer.#{original_theme}.config.js"
|
151
|
+
].flatten.map { |file| file.match?(/^#{@repo_path}/) ? file : @repo_path + file }
|
152
|
+
end
|
153
|
+
|
154
|
+
# These files represent ones such as "./lib/bullet_train/themes/light.rb" which
|
155
|
+
# aren't ejected to the developer's main app, but still need to be changed.
|
156
|
+
def default_files_to_replace(original_theme)
|
157
|
+
# TODO: Add this file and the FileReplacer module once they're added to the main branch.
|
158
|
+
[
|
159
|
+
"/bullet_train-themes-#{original_theme}.gemspec",
|
160
|
+
"/app/assets/config/bullet_train_themes_#{original_theme}_manifest.js",
|
161
|
+
"/lib/tasks/bullet_train/themes/#{original_theme}_tasks.rake",
|
162
|
+
"/test/bullet_train/themes/#{original_theme}_test.rb"
|
163
|
+
].map { |file| @repo_path + file }
|
164
|
+
end
|
165
|
+
|
166
|
+
def files_to_remove_from_main_app(custom_theme)
|
167
|
+
[
|
168
|
+
Dir.glob("./app/assets/stylesheets/#{custom_theme}/**/*.css"),
|
169
|
+
Dir.glob("./app/assets/stylesheets/#{custom_theme}/**/*.scss"),
|
170
|
+
"./app/assets/stylesheets/#{custom_theme}.tailwind.css",
|
171
|
+
"./app/javascript/application.#{custom_theme}.js",
|
172
|
+
"./app/lib/bullet_train/themes/#{custom_theme}.rb",
|
173
|
+
Dir.glob("./app/views/themes/#{custom_theme}/**/*.html.erb"),
|
174
|
+
"./tailwind.mailer.#{custom_theme}.config.js",
|
175
|
+
"./tailwind.#{custom_theme}.config.js",
|
176
|
+
].flatten
|
177
|
+
end
|
178
|
+
|
179
|
+
def files_whose_contents_need_to_be_replaced(custom_theme)
|
180
|
+
[
|
181
|
+
"/app/assets/stylesheets/#{custom_theme}.tailwind.css",
|
182
|
+
"/app/views/themes/#{custom_theme}/layouts/_account.html.erb",
|
183
|
+
"/app/views/themes/#{custom_theme}/layouts/_devise.html.erb",
|
184
|
+
"/bin/rails",
|
185
|
+
"/lib/bullet_train/themes/#{custom_theme}/engine.rb",
|
186
|
+
"/lib/bullet_train/themes/#{custom_theme}/version.rb",
|
187
|
+
"/lib/bullet_train/themes/#{custom_theme}.rb",
|
188
|
+
"/lib/tasks/bullet_train/themes/#{custom_theme}_tasks.rake",
|
189
|
+
"/test/bullet_train/themes/#{custom_theme}_test.rb",
|
190
|
+
"/test/dummy/app/views/layouts/mailer.html.erb",
|
191
|
+
"/test/dummy/config/application.rb",
|
192
|
+
"/bullet_train-themes-#{custom_theme}.gemspec",
|
193
|
+
"/Gemfile",
|
194
|
+
"/README.md"
|
195
|
+
].map { |file| @repo_path + file }
|
196
|
+
end
|
197
|
+
|
198
|
+
def directories_to_remove_from_main_app(custom_theme)
|
199
|
+
[
|
200
|
+
"./app/assets/stylesheets/#{custom_theme}/",
|
201
|
+
"./app/views/themes/#{custom_theme}/",
|
202
|
+
"./app/lib/"
|
203
|
+
].map { |directory| directory unless directory == "./app/lib/" && Dir.empty?(directory) }
|
204
|
+
end
|
205
|
+
|
206
|
+
# Since we're cloning a fresh gem, file names that contain the original
|
207
|
+
# theme stay the same, i.e. - tailwind.light.config.js. However, the names have
|
208
|
+
# already been changed in the main app when the original theme was ejected.
|
209
|
+
# Here, we build the correct string that is in the main app to compare the
|
210
|
+
# files' contents. Then later on we actually rename the new gem's file names.
|
211
|
+
def build_main_app_file_name(original_theme, custom_theme, custom_gem_file)
|
212
|
+
main_app_file = custom_gem_file
|
213
|
+
custom_gem_file_hierarchy = custom_gem_file.split("/")
|
214
|
+
if custom_gem_file_hierarchy.last.match?(original_theme)
|
215
|
+
custom_gem_file_hierarchy.last.gsub!(original_theme, custom_theme)
|
216
|
+
main_app_file = custom_gem_file_hierarchy.join("/")
|
217
|
+
end
|
218
|
+
main_app_file
|
219
|
+
end
|
220
|
+
|
221
|
+
# This addresses one specific file where the hierarchy is
|
222
|
+
# different after the file is ejected into the main application.
|
223
|
+
def adjust_directory_hierarchy(file_name, theme_name)
|
224
|
+
file_name.match?("lib/bullet_train/themes/#{theme_name}") ? file_name.gsub(/\/app/, "") : file_name
|
225
|
+
end
|
226
|
+
|
227
|
+
# i.e. - foo_bar or foo-bar to FooBar
|
228
|
+
def constantize_from_snake_case(str)
|
229
|
+
str.split(/[_|-]/).map(&:capitalize).join
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# TODO: We overwrite/edit/create files a lot in Bullet Train,
|
2
|
+
# so I feel like this and a lot of similar content could go inside its own gem.
|
3
|
+
module BulletTrain
|
4
|
+
module Themes
|
5
|
+
module Light
|
6
|
+
module FileReplacer
|
7
|
+
def self.files_have_same_content?(first_file_name, second_file_name)
|
8
|
+
File.open(first_file_name).readlines == File.open(second_file_name).readlines
|
9
|
+
end
|
10
|
+
|
11
|
+
# Replaces the old content with a brand new file.
|
12
|
+
def self.replace_content(old:, new:)
|
13
|
+
File.write(old, File.open(new).readlines.join(""))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
require "bullet_train/themes/light/version"
|
2
2
|
require "bullet_train/themes/light/engine"
|
3
3
|
require "bullet_train/themes/tailwind_css"
|
4
|
+
require "bullet_train/themes/light/file_replacer"
|
5
|
+
require "bullet_train/themes/light/custom_theme_file_replacer"
|
4
6
|
|
5
7
|
module BulletTrain
|
6
8
|
module Themes
|
7
9
|
module Light
|
8
10
|
# TODO Not sure this is the right place for this in the long-term.
|
9
11
|
mattr_accessor :color, default: :blue
|
12
|
+
mattr_accessor :original_devise_path
|
10
13
|
|
11
14
|
class Theme < BulletTrain::Themes::TailwindCss::Theme
|
12
15
|
def directory_order
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module BulletTrain
|
2
|
+
module Themes
|
3
|
+
module Application
|
4
|
+
def self.eject_theme(theme_name, ejected_theme_name)
|
5
|
+
theme_parts = theme_name.humanize.split.map { |str| str.capitalize }
|
6
|
+
constantized_theme = theme_parts.join
|
7
|
+
humanized_theme = theme_parts.join(" ")
|
8
|
+
|
9
|
+
theme_base_path = `bundle show --paths bullet_train-themes-#{theme_name}`.chomp
|
10
|
+
puts "Ejecting from #{humanized_theme} theme in `#{theme_base_path}`."
|
11
|
+
|
12
|
+
puts "Ejecting Tailwind configuration into `./tailwind.#{ejected_theme_name}.config.js`."
|
13
|
+
`cp #{theme_base_path}/tailwind.#{theme_name}.config.js #{Rails.root}/tailwind.#{ejected_theme_name}.config.js`
|
14
|
+
|
15
|
+
puts "Ejecting Tailwind mailer configuration into `./tailwind.mailer.#{ejected_theme_name}.config.js`."
|
16
|
+
`cp #{theme_base_path}/tailwind.mailer.#{theme_name}.config.js #{Rails.root}/tailwind.mailer.#{ejected_theme_name}.config.js`
|
17
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/#{theme_name}/#{ejected_theme_name}/g" #{Rails.root}/tailwind.mailer.#{ejected_theme_name}.config.js)
|
18
|
+
|
19
|
+
puts "Ejecting stylesheets into `./app/assets/stylesheets/#{ejected_theme_name}`."
|
20
|
+
`mkdir #{Rails.root}/app/assets/stylesheets`
|
21
|
+
`cp -R #{theme_base_path}/app/assets/stylesheets/#{theme_name} #{Rails.root}/app/assets/stylesheets/#{ejected_theme_name}`
|
22
|
+
`cp -R #{theme_base_path}/app/assets/stylesheets/#{theme_name}.tailwind.css #{Rails.root}/app/assets/stylesheets/#{ejected_theme_name}.tailwind.css`
|
23
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{ejected_theme_name}/g" #{Rails.root}/app/assets/stylesheets/#{ejected_theme_name}.tailwind.css)
|
24
|
+
|
25
|
+
puts "Ejecting JavaScript into `./app/javascript/application.#{ejected_theme_name}.js`."
|
26
|
+
`cp #{theme_base_path}/app/javascript/application.#{theme_name}.js #{Rails.root}/app/javascript/application.#{ejected_theme_name}.js`
|
27
|
+
|
28
|
+
puts "Ejecting all theme partials into `./app/views/themes/#{ejected_theme_name}`."
|
29
|
+
`mkdir #{Rails.root}/app/views/themes`
|
30
|
+
`cp -R #{theme_base_path}/app/views/themes/#{theme_name} #{Rails.root}/app/views/themes/#{ejected_theme_name}`
|
31
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/#{theme_name}/#{ejected_theme_name}/g" #{Rails.root}/app/views/themes/#{ejected_theme_name}/layouts/_head.html.erb)
|
32
|
+
|
33
|
+
puts "Cutting local `Procfile.dev` over from `#{theme_name}` to `#{ejected_theme_name}`."
|
34
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/#{theme_name}/#{ejected_theme_name}/g" #{Rails.root}/Procfile.dev)
|
35
|
+
|
36
|
+
puts "Cutting local `package.json` over from `#{theme_name}` to `#{ejected_theme_name}`."
|
37
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/#{theme_name}/#{ejected_theme_name}/g" #{Rails.root}/package.json)
|
38
|
+
|
39
|
+
puts "Cutting `test/system/resolver_system_test.rb` over from `#{theme_name}` to `#{ejected_theme_name}`."
|
40
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{ejected_theme_name}/g" #{Rails.root}/test/system/resolver_system_test.rb)
|
41
|
+
|
42
|
+
# Stub out the class that represents this theme and establishes its inheritance structure.
|
43
|
+
target_path = "#{Rails.root}/app/lib/bullet_train/themes/#{ejected_theme_name}.rb"
|
44
|
+
puts "Stubbing out a class that represents this theme in `.#{target_path}`."
|
45
|
+
`mkdir -p #{Rails.root}/app/lib/bullet_train/themes`
|
46
|
+
`cp #{theme_base_path}/lib/bullet_train/themes/#{theme_name}.rb #{target_path}`
|
47
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/module #{constantized_theme}/module #{ejected_theme_name.titlecase}/g" #{target_path})
|
48
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/TailwindCss/#{constantized_theme}/g" #{target_path})
|
49
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/#{theme_name}/#{ejected_theme_name}/g" #{target_path})
|
50
|
+
["require", "TODO", "mattr_accessor"].each do |thing_to_remove|
|
51
|
+
`grep -v #{thing_to_remove} #{target_path} > #{target_path}.tmp`
|
52
|
+
`mv #{target_path}.tmp #{target_path}`
|
53
|
+
end
|
54
|
+
`standardrb --fix #{target_path}`
|
55
|
+
|
56
|
+
puts "Cutting local project over from `#{theme_name}` to `#{ejected_theme_name}` in `app/helpers/application_helper.rb`."
|
57
|
+
%x(sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/:#{theme_name}/:#{ejected_theme_name}/g" #{Rails.root}/app/helpers/application_helper.rb)
|
58
|
+
|
59
|
+
puts "You must restart `bin/dev` at this point, because of the changes to `Procfile.dev` and `package.json`."
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.release_theme(original_theme_name, args)
|
63
|
+
if original_theme_name != "light"
|
64
|
+
puts "You can only release new themes based off of Bullet Train's Light theme. Please eject a new theme from there, and publish your gem once you've finished making changes.".red
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
puts "Preparing to release your custom theme: ".blue + args[:theme_name]
|
69
|
+
puts ""
|
70
|
+
puts "Before we make a new Ruby gem for your theme, you'll have to set up a GitHub repository first.".blue
|
71
|
+
puts "Hit <Return> and we'll open a browser to GitHub where you can create a new repository.".blue
|
72
|
+
puts "Make sure you name the repository ".blue + "bullet_train-themes-#{args[:theme_name]}"
|
73
|
+
puts ""
|
74
|
+
puts "When you're done, copy the SSH path from the new repository and return here.".blue
|
75
|
+
ask "We'll ask you to paste it to us in the next step."
|
76
|
+
`#{Gem::Platform.local.os == "linux" ? "xdg-open" : "open"} https://github.com/new`
|
77
|
+
|
78
|
+
ssh_path = ask "OK, what was the SSH path? (It should look like `git@github.com:your-account/your-new-repo.git`.)"
|
79
|
+
puts ""
|
80
|
+
puts "Great, you're all set.".blue
|
81
|
+
puts "We'll take it from here, so sit back and enjoy the ride 🚄️".blue
|
82
|
+
puts ""
|
83
|
+
puts "Creating a Ruby gem for ".blue + "#{args[:theme_name]}..."
|
84
|
+
|
85
|
+
Dir.mkdir("local") unless Dir.exist?("./local")
|
86
|
+
if Dir.exist?("./local/bullet_train-themes-#{args[:theme_name]}")
|
87
|
+
raise "You already have a repository named `bullet_train-themes-#{args[:theme_name]}` in `./local`.\n" \
|
88
|
+
"Make sure you delete it first to create an entirely new gem."
|
89
|
+
end
|
90
|
+
`git clone git@github.com:bullet-train-co/bullet_train-themes-light.git ./local/bullet_train-themes-#{args[:theme_name]}`
|
91
|
+
|
92
|
+
custom_file_replacer = BulletTrain::Themes::Light::CustomThemeFileReplacer.new(args[:theme_name])
|
93
|
+
custom_file_replacer.replace_theme("light", args[:theme_name])
|
94
|
+
|
95
|
+
work_tree_flag = "--work-tree=local/bullet_train-themes-#{args[:theme_name]}"
|
96
|
+
git_dir_flag = "--git-dir=local/bullet_train-themes-#{args[:theme_name]}/.git"
|
97
|
+
path = "./local/bullet_train-themes-#{args[:theme_name]}"
|
98
|
+
|
99
|
+
# Set up the proper remote.
|
100
|
+
`git #{work_tree_flag} #{git_dir_flag} remote set-url origin #{ssh_path}`
|
101
|
+
`git #{work_tree_flag} #{git_dir_flag} add .`
|
102
|
+
`git #{work_tree_flag} #{git_dir_flag} commit -m "Add initial files"`
|
103
|
+
|
104
|
+
# Build the gem.
|
105
|
+
`(cd #{path} && gem build bullet_train-themes-#{args[:theme_name]}.gemspec)`
|
106
|
+
`git #{work_tree_flag} #{git_dir_flag} add .`
|
107
|
+
`git #{work_tree_flag} #{git_dir_flag} commit -m "Build gem"`
|
108
|
+
|
109
|
+
# Commit the deleted files on the main application.
|
110
|
+
`git add .`
|
111
|
+
`git commit -m "Remove #{args[:theme_name]} files from application"`
|
112
|
+
|
113
|
+
# Push the gem's source code, but not the last commit in the main application.
|
114
|
+
`git #{work_tree_flag} #{git_dir_flag} push -u origin main`
|
115
|
+
|
116
|
+
puts ""
|
117
|
+
puts ""
|
118
|
+
puts "You're all set! Copy and paste the following commands to publish your gem:".blue
|
119
|
+
puts "cd ./local/bullet_train-themes-#{args[:theme_name]}"
|
120
|
+
puts "gem push bullet_train-themes-#{args[:theme_name]}-1.0.gem && cd ../../"
|
121
|
+
puts ""
|
122
|
+
puts "You may have to wait for some time until the gem can be downloaded via the Gemfile.".blue
|
123
|
+
puts "After a few minutes, run the following command in your main application:".blue
|
124
|
+
puts "bundle add bullet_train-themes-#{args[:theme_name]}"
|
125
|
+
puts "rake bullet_train:themes:#{args[:theme_name]}:install"
|
126
|
+
puts ""
|
127
|
+
puts "Then you'll be ready to use your custom gem in your Bullet Train application.".blue
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.install_theme(theme_name)
|
131
|
+
# Grabs the current theme from
|
132
|
+
# def current_theme
|
133
|
+
# :theme_name
|
134
|
+
# end
|
135
|
+
current_theme_regexp = /(^ :)(.*)/
|
136
|
+
current_theme = nil
|
137
|
+
|
138
|
+
new_lines = []
|
139
|
+
[
|
140
|
+
"./app/helpers/application_helper.rb",
|
141
|
+
"./Procfile.dev",
|
142
|
+
"./package.json"
|
143
|
+
].each do |file|
|
144
|
+
File.open(file, "r") do |f|
|
145
|
+
new_lines = f.readlines
|
146
|
+
new_lines = new_lines.map do |line|
|
147
|
+
# Make sure we get the current theme before trying to replace it in any of the files.
|
148
|
+
# We grab it from the first file in the array above.
|
149
|
+
current_theme = line.scan(current_theme_regexp).flatten.last if line.match?(current_theme_regexp)
|
150
|
+
|
151
|
+
line.gsub!(/#{current_theme}/, theme_name) unless current_theme.nil?
|
152
|
+
line
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
File.open(file, "w") do |f|
|
157
|
+
f.puts new_lines.join
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.clean_theme(theme_name, args)
|
163
|
+
theme_base_path = `bundle show --paths bullet_train-themes-#{theme_name}`.chomp
|
164
|
+
`find app/views/themes/#{args[:theme]} | grep html.erb`.lines.map(&:chomp).each do |path|
|
165
|
+
_, file = path.split("app/views/themes/#{args[:theme]}/")
|
166
|
+
original_theme_path = "#{theme_base_path}/app/views/themes/#{theme_name}/#{file}"
|
167
|
+
if File.read(path) == File.read(original_theme_path)
|
168
|
+
puts "No changes in \`#{path}\` since being ejected. Removing."
|
169
|
+
`rm #{path}`
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.ask(string)
|
175
|
+
puts string.blue
|
176
|
+
$stdin.gets.strip
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -1,56 +1,31 @@
|
|
1
|
+
require "tasks/application"
|
2
|
+
|
1
3
|
namespace :bullet_train do
|
2
4
|
namespace :themes do
|
3
5
|
namespace :light do
|
4
6
|
desc "Fork the \"Light\" theme into your local repository."
|
5
7
|
task :eject, [:destination] => :environment do |task, args|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
puts "Ejecting Tailwind configuration into `./tailwind.#{args[:destination]}.config.js`."
|
10
|
-
`cp #{theme_base_path}/tailwind.light.config.js #{Rails.root}/tailwind.#{args[:destination]}.config.js`
|
11
|
-
|
12
|
-
puts "Ejecting Tailwind mailer configuration into `./tailwind.mailer.#{args[:destination]}.config.js`."
|
13
|
-
`cp #{theme_base_path}/tailwind.mailer.light.config.js #{Rails.root}/tailwind.mailer.#{args[:destination]}.config.js`
|
14
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{args[:destination]}/g" #{Rails.root}/tailwind.mailer.#{args[:destination]}.config.js`
|
15
|
-
|
16
|
-
puts "Ejecting stylesheets into `./app/assets/stylesheets/#{args[:destination]}`."
|
17
|
-
`mkdir #{Rails.root}/app/assets/stylesheets`
|
18
|
-
`cp -R #{theme_base_path}/app/assets/stylesheets/light #{Rails.root}/app/assets/stylesheets/#{args[:destination]}`
|
19
|
-
`cp -R #{theme_base_path}/app/assets/stylesheets/light.tailwind.css #{Rails.root}/app/assets/stylesheets/#{args[:destination]}.tailwind.css`
|
20
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{args[:destination]}/g" #{Rails.root}/app/assets/stylesheets/#{args[:destination]}.tailwind.css`
|
21
|
-
|
22
|
-
puts "Ejecting JavaScript into `./app/javascript/application.#{args[:destination]}.js`."
|
23
|
-
`cp #{theme_base_path}/app/javascript/application.light.js #{Rails.root}/app/javascript/application.#{args[:destination]}.js`
|
24
|
-
|
25
|
-
puts "Ejecting all theme partials into `./app/views/themes/#{args[:destination]}`."
|
26
|
-
`mkdir #{Rails.root}/app/views/themes`
|
27
|
-
`cp -R #{theme_base_path}/app/views/themes/light #{Rails.root}/app/views/themes/#{args[:destination]}`
|
28
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{args[:destination]}/g" #{Rails.root}/app/views/themes/#{args[:destination]}/layouts/_head.html.erb`
|
29
|
-
|
30
|
-
puts "Cutting local `Procfile.dev` over from `light` to `#{args[:destination]}`."
|
31
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{args[:destination]}/g" #{Rails.root}/Procfile.dev`
|
8
|
+
BulletTrain::Themes::Application.eject_theme(get_theme_name_from_task(task), args[:destination])
|
9
|
+
end
|
32
10
|
|
33
|
-
|
34
|
-
|
11
|
+
desc "Publish your custom theme theme as a Ruby gem."
|
12
|
+
task :release, [:theme_name] => :environment do |task, args|
|
13
|
+
BulletTrain::Themes::Application.release_theme(get_theme_name_from_task(task), args)
|
14
|
+
end
|
35
15
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
`cp #{theme_base_path}/lib/bullet_train/themes/light.rb #{target_path}`
|
41
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/module Light/module #{args[:destination].titlecase}/g" #{target_path}`
|
42
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/TailwindCss/Light/g" #{target_path}`
|
43
|
-
`sed -i #{'""' if `echo $OSTYPE`.include?("darwin")} "s/light/#{args[:destination]}/g" #{target_path}`
|
44
|
-
["require", "TODO", "mattr_accessor"].each do |thing_to_remove|
|
45
|
-
`grep -v #{thing_to_remove} #{target_path} > #{target_path}.tmp`
|
46
|
-
`mv #{target_path}.tmp #{target_path}`
|
47
|
-
end
|
48
|
-
`standardrb --fix #{target_path}`
|
16
|
+
desc "Install this theme to your main application."
|
17
|
+
task :install do |task|
|
18
|
+
BulletTrain::Themes::Application.install_theme(get_theme_name_from_task(task))
|
19
|
+
end
|
49
20
|
|
50
|
-
|
51
|
-
|
21
|
+
desc "List view partials in theme that haven't changed since ejection from \"Light\"."
|
22
|
+
task :clean, [:theme] => :environment do |task, args|
|
23
|
+
BulletTrain::Themes::Application.clean_theme(get_theme_name_from_task(task), args)
|
24
|
+
end
|
52
25
|
|
53
|
-
|
26
|
+
# Grabs the theme name from task, i.e. - bullet_train:theme:light:eject.
|
27
|
+
def get_theme_name_from_task(task)
|
28
|
+
task.name.split(":")[2]
|
54
29
|
end
|
55
30
|
end
|
56
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train-themes-light
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.49
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- app/assets/stylesheets/light/actiontext.css
|
69
69
|
- app/assets/stylesheets/light/application.css
|
70
70
|
- app/assets/stylesheets/light/bulk_actions.css
|
71
|
+
- app/assets/stylesheets/light/devise.css
|
71
72
|
- app/assets/stylesheets/light/electron.css
|
72
73
|
- app/assets/stylesheets/light/fields/cloudinary_image.css
|
73
74
|
- app/assets/stylesheets/light/fields/date_field.css
|
@@ -124,8 +125,11 @@ files:
|
|
124
125
|
- app/views/themes/light/workflow/_box.html.erb
|
125
126
|
- config/routes.rb
|
126
127
|
- lib/bullet_train/themes/light.rb
|
128
|
+
- lib/bullet_train/themes/light/custom_theme_file_replacer.rb
|
127
129
|
- lib/bullet_train/themes/light/engine.rb
|
130
|
+
- lib/bullet_train/themes/light/file_replacer.rb
|
128
131
|
- lib/bullet_train/themes/light/version.rb
|
132
|
+
- lib/tasks/application.rb
|
129
133
|
- lib/tasks/bullet_train/themes/light_tasks.rake
|
130
134
|
- tailwind.light.config.js
|
131
135
|
homepage: https://github.com/bullet-train-co/bullet_train-themes-light
|