bullet_train-themes-light 1.0.44 → 1.0.49
Sign up to get free protection for your applications and to get access to all the features.
- 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
|