kaze 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +21 -2
- data/lib/kaze/commands/install_command.rb +24 -7
- data/lib/kaze/commands/installs_hotwire_stack.rb +62 -0
- data/lib/kaze/commands/{install_inertia_stacks.rb → installs_inertia_stacks.rb} +19 -17
- data/lib/kaze/version.rb +1 -1
- data/stubs/default/app/validators/lowercase_validator.rb +1 -0
- data/stubs/default/app/views/layouts/mailer.html.erb +3 -1
- data/stubs/default/app/views/layouts/mailer.text.erb +3 -1
- data/stubs/default/config/routes.rb +1 -1
- data/stubs/hotwire/Procfile.dev +2 -0
- data/stubs/hotwire/app/components/application_logo_component.rb +14 -0
- data/stubs/hotwire/app/components/auth_session_status_component.rb +17 -0
- data/stubs/hotwire/app/components/danger_button_component.rb +13 -0
- data/stubs/hotwire/app/components/dropdown_component.html.erb +20 -0
- data/stubs/hotwire/app/components/dropdown_component.rb +15 -0
- data/stubs/hotwire/app/components/dropdown_link_component.rb +12 -0
- data/stubs/hotwire/app/components/input_error_component.rb +18 -0
- data/stubs/hotwire/app/components/input_label_component.rb +13 -0
- data/stubs/hotwire/app/components/modal_component.html.erb +62 -0
- data/stubs/hotwire/app/components/modal_component.rb +14 -0
- data/stubs/hotwire/app/components/nav_link_component.rb +15 -0
- data/stubs/hotwire/app/components/primary_button_component.rb +13 -0
- data/stubs/hotwire/app/components/responsive_nav_link_component.rb +15 -0
- data/stubs/hotwire/app/components/secondary_button_component.rb +13 -0
- data/stubs/hotwire/app/components/text_input_component.rb +11 -0
- data/stubs/hotwire/app/controllers/application_controller.rb +3 -0
- data/stubs/hotwire/app/controllers/auth/authenticated_session_controller.rb +29 -0
- data/stubs/hotwire/app/controllers/auth/new_password_controller.rb +19 -0
- data/stubs/hotwire/app/controllers/auth/password_reset_link_controller.rb +19 -0
- data/stubs/hotwire/app/controllers/auth/registered_user_controller.rb +23 -0
- data/stubs/hotwire/app/controllers/dashboard_controller.rb +4 -0
- data/stubs/hotwire/app/controllers/password_controller.rb +11 -0
- data/stubs/hotwire/app/controllers/profile_controller.rb +33 -0
- data/stubs/hotwire/app/controllers/welcome_controller.rb +7 -0
- data/stubs/hotwire/app/javascript/alpinejs.js +2 -0
- data/stubs/hotwire/app/javascript/application.js +8 -0
- data/stubs/hotwire/app/views/auth/forgot_password.html.erb +23 -0
- data/stubs/hotwire/app/views/auth/login.html.erb +40 -0
- data/stubs/hotwire/app/views/auth/register.html.erb +47 -0
- data/stubs/hotwire/app/views/auth/reset_password.html.erb +28 -0
- data/stubs/hotwire/app/views/dashboard/index.html.erb +15 -0
- data/stubs/hotwire/app/views/layouts/_navigation.html.erb +92 -0
- data/stubs/hotwire/app/views/layouts/application.html.erb +42 -0
- data/stubs/hotwire/app/views/layouts/guest.html.erb +33 -0
- data/stubs/hotwire/app/views/profile/edit.html.erb +27 -0
- data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +48 -0
- data/stubs/hotwire/app/views/profile/partials/_update_password_form.html.erb +58 -0
- data/stubs/hotwire/app/views/profile/partials/_update_profile_information_form.html.erb +49 -0
- data/stubs/hotwire/app/views/welcome/index.html.erb +68 -0
- data/stubs/hotwire/config/importmap.rb +3 -0
- data/stubs/hotwire/config/tailwind.config.js +23 -0
- data/stubs/inertia-common/app/controllers/concerns/authenticate.rb +34 -0
- data/stubs/{default → inertia-common}/app/controllers/dashboard_controller.rb +1 -1
- data/stubs/inertia-common/bin/vite +27 -0
- data/stubs/inertia-common/config/vite.json +16 -0
- data/stubs/inertia-react-ts/app/views/layouts/application.html.erb +0 -4
- data/stubs/inertia-react-ts/config/tailwind.config.js +1 -1
- data/stubs/inertia-react-ts/package.json +24 -24
- data/stubs/inertia-vue-ts/app/javascript/Pages/Welcome.vue +1 -1
- data/stubs/inertia-vue-ts/app/views/layouts/application.html.erb +0 -4
- data/stubs/inertia-vue-ts/config/tailwind.config.js +1 -1
- metadata +63 -18
- data/stubs/default/config/vite.json +0 -16
- /data/stubs/{default → hotwire}/app/controllers/concerns/authenticate.rb +0 -0
- /data/stubs/{default → hotwire}/bin/vite +0 -0
- /data/stubs/{default → inertia-common}/Procfile.dev +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/application_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/auth/authenticated_session_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/auth/new_password_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/auth/password_reset_link_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/auth/registered_user_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/concerns/handle_inertia_requests.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/concerns/verify_csrf_token.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/password_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/profile_controller.rb +0 -0
- /data/stubs/{default → inertia-common}/app/controllers/welcome_controller.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c2c180c5d3390cc6b2013e98ce172091691001be25971dfc2f2f28fe7022eaf1
|
|
4
|
+
data.tar.gz: ddc60156cf90ab2827ea0907e0f7d68e6bc4c760963ad271809b80132b0a7884
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a47cce2a4bd167ac9f57ac2c367794f61f7354e3400619112abd2482d59a1341ccbe1bbd6881f61104404f4b7a87c59600fe1889abbd5577ab8f12d22308ef6
|
|
7
|
+
data.tar.gz: 0f885b972c32e66757b2412481b8cce0aacc03fd7512bebbc41e007bc4e715afec41afc36c946fe05e462a5c26256cfbe47955ce61e66508df9467be82ddab77
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Heavily inspired by [Laravel Breeze](https://github.com/laravel/breeze), this ge
|
|
|
4
4
|
|
|
5
5
|
[Kaze](https://github.com/gtkvn/kaze) is a minimal, simple implementation of all of Rails's authentication features, including login, registration, password reset. In addition, Kaze includes a simple "profile" page where the user may update their name, email address, and password.
|
|
6
6
|
|
|
7
|
-
Kaze provides scaffolding options based on Inertia, with the choice of using Vue or React for the Inertia-based scaffolding.
|
|
7
|
+
Kaze provides scaffolding options based on [Hotwire](https://hotwired.dev) or [Inertia](https://inertiajs.com), with the choice of using Vue or React for the Inertia-based scaffolding.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -18,11 +18,30 @@ gem install kaze
|
|
|
18
18
|
|
|
19
19
|
Once Kaze is installed, you may scaffold your application using one of the Kaze "stacks" discussed in the documentation below.
|
|
20
20
|
|
|
21
|
+
## Kaze & Hotwire
|
|
22
|
+
|
|
23
|
+
The default Kaze "stack" is the Hotwire stack. Hotwire is a powerful way to building dynamic, reactive, front-end UIs primarily using Ruby and ERB templates without using much JavaScript by sending HTML instead of JSON over the wire.
|
|
24
|
+
|
|
25
|
+
The Hotwire stack may be installed by invoking the `install` command with no other additional arguments inside your app directory.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
kaze install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
After Kaze's scaffolding is installed, you may start your application:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
bin/setup
|
|
35
|
+
bin/dev
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Next, you may navigate to your application's `/login` or `/register` URLs in your web browser.
|
|
39
|
+
|
|
21
40
|
## Kaze & React / Vue
|
|
22
41
|
|
|
23
42
|
Kaze offers React and Vue scaffolding via an Inertia frontend implementation. Inertia allows you to build modern, single-page React and Vue applications using classic server-side routing and controllers.
|
|
24
43
|
|
|
25
|
-
Inertia lets you enjoy the frontend power of React and Vue combined with the incredible backend productivity of Rails and lightning-fast Vite compilation. To use an Inertia stack, specify
|
|
44
|
+
Inertia lets you enjoy the frontend power of React and Vue combined with the incredible backend productivity of Rails and lightning-fast Vite compilation. To use an Inertia stack, specify `react` or `vue` as your desired stack when executing the `install` command inside your app directory:
|
|
26
45
|
|
|
27
46
|
```
|
|
28
47
|
kaze install react
|
|
@@ -4,10 +4,15 @@ require "open3"
|
|
|
4
4
|
require "thor"
|
|
5
5
|
|
|
6
6
|
class Kaze::Commands::InstallCommand < Thor
|
|
7
|
-
include Kaze::Commands::
|
|
7
|
+
include Kaze::Commands::InstallsHotwireStack
|
|
8
|
+
include Kaze::Commands::InstallsInertiaStacks
|
|
8
9
|
|
|
9
|
-
desc "install [STACK]", "Install the Kaze controllers and resources. Supported stacks: react, vue."
|
|
10
|
+
desc "install [STACK]", "Install the Kaze controllers and resources. Supported stacks: hotwire, react, vue."
|
|
10
11
|
def install(stack = "hotwire")
|
|
12
|
+
if stack == "hotwire"
|
|
13
|
+
return install_hotwire_stack
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
if stack == "react"
|
|
12
17
|
return install_inertia_react_stack
|
|
13
18
|
end
|
|
@@ -16,19 +21,31 @@ class Kaze::Commands::InstallCommand < Thor
|
|
|
16
21
|
return install_inertia_vue_stack
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
say "Invalid stack. Supported stacks are [react], [vue].", :red
|
|
24
|
+
say "Invalid stack. Supported stacks are [hotwire], [react], [vue].", :red
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
private
|
|
23
28
|
|
|
24
|
-
def
|
|
29
|
+
def install_gems(gems = [], group = nil)
|
|
30
|
+
installed_gems = Bundler::Definition.build("#{Dir.pwd}/Gemfile", nil, {}).dependencies.map(&:name)
|
|
31
|
+
|
|
32
|
+
gem_being_installed = gems.map { |gem| gem unless installed_gems.include?(gem) }.compact
|
|
33
|
+
|
|
34
|
+
return true if gem_being_installed.empty?
|
|
35
|
+
|
|
36
|
+
status = run_command("bundle add #{gem_being_installed.join(" ")}#{group ? " --group \"#{group}\"" : ""}")
|
|
37
|
+
|
|
38
|
+
status.success?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def remove_gems(gems = [])
|
|
25
42
|
installed_gems = Bundler::Definition.build("#{Dir.pwd}/Gemfile", nil, {}).dependencies.map(&:name)
|
|
26
43
|
|
|
27
|
-
|
|
44
|
+
gems_being_removed = gems.map { |gem| gem if installed_gems.include?(gem) }.compact
|
|
28
45
|
|
|
29
|
-
return true if
|
|
46
|
+
return true if gems_being_removed.empty?
|
|
30
47
|
|
|
31
|
-
status = run_command("bundle
|
|
48
|
+
status = run_command("bundle remove #{gems_being_removed.join(" ")}")
|
|
32
49
|
|
|
33
50
|
status.success?
|
|
34
51
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Kaze::Commands::InstallsHotwireStack
|
|
2
|
+
private
|
|
3
|
+
|
|
4
|
+
def install_hotwire_stack
|
|
5
|
+
# Gems...
|
|
6
|
+
return unless remove_gems([ "sprockets-rails" ])
|
|
7
|
+
return unless install_gems([ "propshaft", "view_component", "tailwindcss-rails", "turbo-rails", "dotenv", "bcrypt" ])
|
|
8
|
+
return unless install_gems([ "hotwire-livereload" ], "development")
|
|
9
|
+
|
|
10
|
+
# Controllers...
|
|
11
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/hotwire/app/controllers", "#{Dir.pwd}/app/controllers")
|
|
12
|
+
|
|
13
|
+
# Models...
|
|
14
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/models", "#{Dir.pwd}/app/models")
|
|
15
|
+
|
|
16
|
+
# Forms...
|
|
17
|
+
ensure_directory_exists("#{Dir.pwd}/app/forms")
|
|
18
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/forms", "#{Dir.pwd}/app/forms")
|
|
19
|
+
|
|
20
|
+
# Validators...
|
|
21
|
+
ensure_directory_exists("#{Dir.pwd}/app/validators")
|
|
22
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/validators", "#{Dir.pwd}/app/validators")
|
|
23
|
+
|
|
24
|
+
# Mailers...
|
|
25
|
+
ensure_directory_exists("#{Dir.pwd}/app/mailers")
|
|
26
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/mailers", "#{Dir.pwd}/app/mailers")
|
|
27
|
+
|
|
28
|
+
# Views...
|
|
29
|
+
ensure_directory_exists("#{Dir.pwd}/app/views/layouts")
|
|
30
|
+
ensure_directory_exists("#{Dir.pwd}/app/views/user_mailer")
|
|
31
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/hotwire/app/views", "#{Dir.pwd}/app/views")
|
|
32
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/views/layouts/mailer.html.erb", "#{Dir.pwd}/app/views/layouts/mailer.html.erb")
|
|
33
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/views/layouts/mailer.text.erb", "#{Dir.pwd}/app/views/layouts/mailer.text.erb")
|
|
34
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/views/user_mailer/reset_password.html.erb", "#{Dir.pwd}/app/views/user_mailer/reset_password.html.erb")
|
|
35
|
+
|
|
36
|
+
# Components + Pages...
|
|
37
|
+
ensure_directory_exists("#{Dir.pwd}/app/components")
|
|
38
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/hotwire/app/components", "#{Dir.pwd}/app/components")
|
|
39
|
+
ensure_directory_exists("#{Dir.pwd}/app/javascript")
|
|
40
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/hotwire/app/javascript", "#{Dir.pwd}/app/javascript")
|
|
41
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/hotwire/config/importmap.rb", "#{Dir.pwd}/config/importmap.rb")
|
|
42
|
+
|
|
43
|
+
# Tests...
|
|
44
|
+
|
|
45
|
+
# Routes...
|
|
46
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/config/routes.rb", "#{Dir.pwd}/config/routes.rb")
|
|
47
|
+
|
|
48
|
+
# Migrations...
|
|
49
|
+
install_migrations
|
|
50
|
+
|
|
51
|
+
# Tailwind...
|
|
52
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/assets/stylesheets/application.css", "#{Dir.pwd}/app/assets/stylesheets/application.css")
|
|
53
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/assets/stylesheets/application.tailwind.css", "#{Dir.pwd}/app/assets/stylesheets/application.tailwind.css")
|
|
54
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/hotwire/config/tailwind.config.js", "#{Dir.pwd}/config/tailwind.config.js")
|
|
55
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/bin/dev", "#{Dir.pwd}/bin/dev")
|
|
56
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/hotwire/Procfile.dev", "#{Dir.pwd}/Procfile.dev")
|
|
57
|
+
run_command("rails tailwindcss:build")
|
|
58
|
+
|
|
59
|
+
say ""
|
|
60
|
+
say "Kaze scaffolding installed successfully.", :green
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
module Kaze::Commands::
|
|
1
|
+
module Kaze::Commands::InstallsInertiaStacks
|
|
2
2
|
private
|
|
3
3
|
|
|
4
4
|
def install_inertia_react_stack
|
|
5
|
-
#
|
|
6
|
-
return unless
|
|
5
|
+
# Gems...
|
|
6
|
+
return unless remove_gems([ "sprockets-rails" ])
|
|
7
|
+
return unless install_gems([ "propshaft", "tailwindcss-rails", "inertia_rails", "vite_rails", "dotenv", "bcrypt", "js-routes" ])
|
|
7
8
|
|
|
8
9
|
# NPM Packages...
|
|
9
10
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-react-ts/package.json", "#{Dir.pwd}/package.json")
|
|
10
11
|
|
|
11
12
|
# Controllers...
|
|
12
|
-
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/
|
|
13
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/app/controllers", "#{Dir.pwd}/app/controllers")
|
|
13
14
|
|
|
14
15
|
# Models...
|
|
15
16
|
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/models", "#{Dir.pwd}/app/models")
|
|
@@ -22,6 +23,10 @@ module Kaze::Commands::InstallInertiaStacks
|
|
|
22
23
|
ensure_directory_exists("#{Dir.pwd}/app/validators")
|
|
23
24
|
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/validators", "#{Dir.pwd}/app/validators")
|
|
24
25
|
|
|
26
|
+
# Mailers...
|
|
27
|
+
ensure_directory_exists("#{Dir.pwd}/app/mailers")
|
|
28
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/mailers", "#{Dir.pwd}/app/mailers")
|
|
29
|
+
|
|
25
30
|
# Views...
|
|
26
31
|
ensure_directory_exists("#{Dir.pwd}/app/views/layouts")
|
|
27
32
|
ensure_directory_exists("#{Dir.pwd}/app/views/user_mailer")
|
|
@@ -30,10 +35,6 @@ module Kaze::Commands::InstallInertiaStacks
|
|
|
30
35
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/views/layouts/mailer.text.erb", "#{Dir.pwd}/app/views/layouts/mailer.text.erb")
|
|
31
36
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/views/user_mailer/reset_password.html.erb", "#{Dir.pwd}/app/views/user_mailer/reset_password.html.erb")
|
|
32
37
|
|
|
33
|
-
# Mailers...
|
|
34
|
-
ensure_directory_exists("#{Dir.pwd}/app/mailers")
|
|
35
|
-
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/mailers", "#{Dir.pwd}/app/mailers")
|
|
36
|
-
|
|
37
38
|
# Components + Pages...
|
|
38
39
|
ensure_directory_exists("#{Dir.pwd}/app/javascript")
|
|
39
40
|
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/inertia-react-ts/app/javascript", "#{Dir.pwd}/app/javascript")
|
|
@@ -50,12 +51,12 @@ module Kaze::Commands::InstallInertiaStacks
|
|
|
50
51
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/assets/stylesheets/application.css", "#{Dir.pwd}/app/assets/stylesheets/application.css")
|
|
51
52
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/assets/stylesheets/application.tailwind.css", "#{Dir.pwd}/app/assets/stylesheets/application.tailwind.css")
|
|
52
53
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-react-ts/config/tailwind.config.js", "#{Dir.pwd}/config/tailwind.config.js")
|
|
53
|
-
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/
|
|
54
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/config/vite.json", "#{Dir.pwd}/config/vite.json")
|
|
54
55
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-react-ts/tsconfig.json", "#{Dir.pwd}/tsconfig.json")
|
|
55
56
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-react-ts/vite.config.ts", "#{Dir.pwd}/vite.config.ts")
|
|
56
57
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/bin/dev", "#{Dir.pwd}/bin/dev")
|
|
57
|
-
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/
|
|
58
|
-
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/
|
|
58
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/bin/vite", "#{Dir.pwd}/bin/vite")
|
|
59
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/Procfile.dev", "#{Dir.pwd}/Procfile.dev")
|
|
59
60
|
run_command("rails generate js_routes:middleware")
|
|
60
61
|
|
|
61
62
|
say ""
|
|
@@ -76,14 +77,15 @@ module Kaze::Commands::InstallInertiaStacks
|
|
|
76
77
|
end
|
|
77
78
|
|
|
78
79
|
def install_inertia_vue_stack
|
|
79
|
-
#
|
|
80
|
-
return unless
|
|
80
|
+
# Gems...
|
|
81
|
+
return unless remove_gems([ "sprockets-rails" ])
|
|
82
|
+
return unless install_gems([ "propshaft", "tailwindcss-rails", "inertia_rails", "vite_rails", "dotenv", "bcrypt", "js-routes" ])
|
|
81
83
|
|
|
82
84
|
# NPM Packages...
|
|
83
85
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-vue-ts/package.json", "#{Dir.pwd}/package.json")
|
|
84
86
|
|
|
85
87
|
# Controllers...
|
|
86
|
-
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/
|
|
88
|
+
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/app/controllers", "#{Dir.pwd}/app/controllers")
|
|
87
89
|
|
|
88
90
|
# Models...
|
|
89
91
|
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/app/models", "#{Dir.pwd}/app/models")
|
|
@@ -124,12 +126,12 @@ module Kaze::Commands::InstallInertiaStacks
|
|
|
124
126
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/assets/stylesheets/application.css", "#{Dir.pwd}/app/assets/stylesheets/application.css")
|
|
125
127
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/app/assets/stylesheets/application.tailwind.css", "#{Dir.pwd}/app/assets/stylesheets/application.tailwind.css")
|
|
126
128
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-vue-ts/config/tailwind.config.js", "#{Dir.pwd}/config/tailwind.config.js")
|
|
127
|
-
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/
|
|
129
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/config/vite.json", "#{Dir.pwd}/config/vite.json")
|
|
128
130
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-vue-ts/tsconfig.json", "#{Dir.pwd}/tsconfig.json")
|
|
129
131
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-vue-ts/vite.config.ts", "#{Dir.pwd}/vite.config.ts")
|
|
130
132
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/bin/dev", "#{Dir.pwd}/bin/dev")
|
|
131
|
-
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/
|
|
132
|
-
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/
|
|
133
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/bin/vite", "#{Dir.pwd}/bin/vite")
|
|
134
|
+
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/Procfile.dev", "#{Dir.pwd}/Procfile.dev")
|
|
133
135
|
run_command("rails generate js_routes:middleware")
|
|
134
136
|
|
|
135
137
|
say ""
|
data/lib/kaze/version.rb
CHANGED
|
@@ -340,13 +340,15 @@ img {
|
|
|
340
340
|
<%= yield %>
|
|
341
341
|
|
|
342
342
|
<!-- Subcopy -->
|
|
343
|
+
<% if content_for?(:subcopy) %>
|
|
343
344
|
<table class="subcopy" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
|
344
345
|
<tr>
|
|
345
346
|
<td>
|
|
346
|
-
<%= yield
|
|
347
|
+
<%= yield :subcopy %>
|
|
347
348
|
</td>
|
|
348
349
|
</tr>
|
|
349
350
|
</table>
|
|
351
|
+
<% end %>
|
|
350
352
|
|
|
351
353
|
</td>
|
|
352
354
|
</tr>
|
|
@@ -17,7 +17,7 @@ Rails.application.routes.draw do
|
|
|
17
17
|
|
|
18
18
|
post "logout", to: "auth/authenticated_session#destroy", as: :logout
|
|
19
19
|
|
|
20
|
-
get "dashboard", to: "dashboard#
|
|
20
|
+
get "dashboard", to: "dashboard#index", as: :dashboard
|
|
21
21
|
|
|
22
22
|
get "profile", to: "profile#edit", as: :profile_edit
|
|
23
23
|
patch "profile", to: "profile#update", as: :profile_update
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class ApplicationLogoComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<svg viewBox="0 -6 32 32" xmlns="http://www.w3.org/2000/svg" <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<g fill="none" fill-rule="evenodd">
|
|
5
|
+
<path d="M0-6h32v32H0z"/>
|
|
6
|
+
<path fill="#c00" fill-rule="nonzero" d="M.985 19.636s.422-4.163 3.375-9.087c2.954-4.924 7.99-8.65 12.083-9.017 8.144-.816 15.46 6.485 15.46 6.485s-.24.168-.494.38C23.42 2.49 18.54 5.274 17.005 6.02c-7.033 3.925-4.91 13.616-4.91 13.616H.987zM24.137 2.32c-.45-.182-.9-.35-1.364-.505l.056-.93c.885.254 1.237.423 1.363.493l-.056.943zM22.8 5.304c.45.028.915.084 1.393.183l-.056.872c-.464-.1-.928-.155-1.392-.17l.056-.885zM17.597.913c-.407 0-.815.015-1.223.058l-.268-.83c.465-.056.915-.084 1.35-.084l.282.858h-.14zm.676 5.178c.35-.154.76-.31 1.237-.45l.31.93c-.41.125-.817.294-1.225.49l-.323-.97zm-6.386-3.7c-.366.184-.718.395-1.083.62l-.647-.985c.38-.225.745-.42 1.097-.604l.633.97zm2.883 6.33c.252-.323.548-.646.87-.942l.634.957c-.31.323-.59.647-.83 1L14.77 8.72zm-2.04 4.53c.112-.506.24-1.027.422-1.547l1.012.802c-.14.548-.24 1.097-.295 1.645l-1.14-.9zM6.57 6.57c-.34.35-.662.73-.958 1.11L4.53 6.752c.323-.352.674-.704 1.04-1.055l1 .872zm-4.25 6.286c-.224.52-.52 1.21-.702 1.688L0 13.954c.14-.38.436-1.084.703-1.69l1.618.592zm10.2 3.967l1.518.548c.084.663.21 1.28.337 1.83l-1.688-.605c-.07-.422-.14-1.027-.168-1.772z"/>
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
|
9
|
+
ERB
|
|
10
|
+
|
|
11
|
+
def initialize(attributes = {})
|
|
12
|
+
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class AuthSessionStatusComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<div <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= @status %>
|
|
5
|
+
</div>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
@status = attributes[:status]
|
|
10
|
+
attributes[:class] = "font-medium text-sm text-green-600 dark:text-green-400#{" #{attributes[:class]}" if attributes[:class]}"
|
|
11
|
+
@attributes = attributes.without(:status).map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render?
|
|
15
|
+
@status.present?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class DangerButtonComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<button <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
</button>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
attributes[:type] = attributes[:type] || "submit"
|
|
10
|
+
attributes[:class] = "inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150#{" #{attributes[:class]}" if attributes[:class]}"
|
|
11
|
+
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<div class="relative" x-data="{ open: false }" @click.outside="open = false" @close.stop="open = false">
|
|
2
|
+
<div @click="open = ! open">
|
|
3
|
+
<%= trigger %>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div x-show="open"
|
|
7
|
+
x-transition:enter="transition ease-out duration-200"
|
|
8
|
+
x-transition:enter-start="opacity-0 scale-95"
|
|
9
|
+
x-transition:enter-end="opacity-100 scale-100"
|
|
10
|
+
x-transition:leave="transition ease-in duration-75"
|
|
11
|
+
x-transition:leave-start="opacity-100 scale-100"
|
|
12
|
+
x-transition:leave-end="opacity-0 scale-95"
|
|
13
|
+
class="absolute z-50 mt-2 <%= @width %> rounded-md shadow-lg <%= @alignment_classes %>"
|
|
14
|
+
style="display: none;"
|
|
15
|
+
@click="open = false">
|
|
16
|
+
<div class="rounded-md ring-1 ring-black ring-opacity-5 <%= @content_classes %>">
|
|
17
|
+
<%= content %>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class DropdownComponent < ViewComponent::Base
|
|
2
|
+
renders_one :trigger
|
|
3
|
+
|
|
4
|
+
def initialize(align: "right", width: "48", content_classes: "py-1 bg-white dark:bg-gray-700")
|
|
5
|
+
if align == "left"
|
|
6
|
+
@alignment_classes = "ltr:origin-top-left rtl:origin-top-right start-0"
|
|
7
|
+
elsif align == "top"
|
|
8
|
+
@alignment_classes = "origin-top"
|
|
9
|
+
else
|
|
10
|
+
@alignment_classes = "ltr:origin-top-right rtl:origin-top-left end-0"
|
|
11
|
+
end
|
|
12
|
+
@width = width == "48" ? "w-48" : width
|
|
13
|
+
@content_classes = content_classes
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class DropdownLinkComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<a <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
</a>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
attributes[:class] = "block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out#{" #{attributes[:class]}" if attributes[:class]}"
|
|
10
|
+
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class InputErrorComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<div <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<p class="text-sm text-red-600 dark:text-red-400">
|
|
5
|
+
<%= @message %>
|
|
6
|
+
</p>
|
|
7
|
+
</div>
|
|
8
|
+
ERB
|
|
9
|
+
|
|
10
|
+
def initialize(attributes = {})
|
|
11
|
+
@message = attributes[:message]
|
|
12
|
+
@attributes = attributes.without(:message).map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def render?
|
|
16
|
+
@message.present?
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class InputLabelComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<a <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= @value ? @value : content %>
|
|
5
|
+
</a>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
@value = attributes[:value] || nil
|
|
10
|
+
attributes[:class] = "block font-medium text-sm text-gray-700 dark:text-gray-300#{" #{attributes[:class]}" if attributes[:class]}"
|
|
11
|
+
@attributes = attributes.without(:value).map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<div
|
|
2
|
+
x-data="{
|
|
3
|
+
show: <%= @show %>,
|
|
4
|
+
focusables() {
|
|
5
|
+
// All focusable element types...
|
|
6
|
+
let selector = 'a, button, input:not([type=\'hidden\']), textarea, select, details, [tabindex]:not([tabindex=\'-1\'])'
|
|
7
|
+
return [...$el.querySelectorAll(selector)]
|
|
8
|
+
// All non-disabled elements...
|
|
9
|
+
.filter(el => ! el.hasAttribute('disabled'))
|
|
10
|
+
},
|
|
11
|
+
firstFocusable() { return this.focusables()[0] },
|
|
12
|
+
lastFocusable() { return this.focusables().slice(-1)[0] },
|
|
13
|
+
nextFocusable() { return this.focusables()[this.nextFocusableIndex()] || this.firstFocusable() },
|
|
14
|
+
prevFocusable() { return this.focusables()[this.prevFocusableIndex()] || this.lastFocusable() },
|
|
15
|
+
nextFocusableIndex() { return (this.focusables().indexOf(document.activeElement) + 1) % (this.focusables().length + 1) },
|
|
16
|
+
prevFocusableIndex() { return Math.max(0, this.focusables().indexOf(document.activeElement)) -1 },
|
|
17
|
+
}"
|
|
18
|
+
x-init="$watch('show', value => {
|
|
19
|
+
if (value) {
|
|
20
|
+
document.body.classList.add('overflow-y-hidden');
|
|
21
|
+
<%= @attributes.has_key?(:focusable) ? 'setTimeout(() => firstFocusable().focus(), 100)' : '' %>
|
|
22
|
+
} else {
|
|
23
|
+
document.body.classList.remove('overflow-y-hidden');
|
|
24
|
+
}
|
|
25
|
+
})"
|
|
26
|
+
x-on:open-modal.window="$event.detail == '<%= @name %>' ? show = true : null"
|
|
27
|
+
x-on:close-modal.window="$event.detail == '<%= @name %>' ? show = false : null"
|
|
28
|
+
x-on:close.stop="show = false"
|
|
29
|
+
x-on:keydown.escape.window="show = false"
|
|
30
|
+
x-on:keydown.tab.prevent="$event.shiftKey || nextFocusable().focus()"
|
|
31
|
+
x-on:keydown.shift.tab.prevent="prevFocusable().focus()"
|
|
32
|
+
x-show="show"
|
|
33
|
+
class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50"
|
|
34
|
+
style="display: <%= @show ? 'block' : 'none' %>;"
|
|
35
|
+
>
|
|
36
|
+
<div
|
|
37
|
+
x-show="show"
|
|
38
|
+
class="fixed inset-0 transform transition-all"
|
|
39
|
+
x-on:click="show = false"
|
|
40
|
+
x-transition:enter="ease-out duration-300"
|
|
41
|
+
x-transition:enter-start="opacity-0"
|
|
42
|
+
x-transition:enter-end="opacity-100"
|
|
43
|
+
x-transition:leave="ease-in duration-200"
|
|
44
|
+
x-transition:leave-start="opacity-100"
|
|
45
|
+
x-transition:leave-end="opacity-0"
|
|
46
|
+
>
|
|
47
|
+
<div class="absolute inset-0 bg-gray-500 dark:bg-gray-900 opacity-75"></div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div
|
|
51
|
+
x-show="show"
|
|
52
|
+
class="mb-6 bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full <%= @max_width %> sm:mx-auto"
|
|
53
|
+
x-transition:enter="ease-out duration-300"
|
|
54
|
+
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
55
|
+
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
|
56
|
+
x-transition:leave="ease-in duration-200"
|
|
57
|
+
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
|
|
58
|
+
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
59
|
+
>
|
|
60
|
+
<%= content %>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class ModalComponent < ViewComponent::Base
|
|
2
|
+
def initialize(attributes = {})
|
|
3
|
+
@name = attributes[:name]
|
|
4
|
+
@show = attributes[:show] || false
|
|
5
|
+
@max_width = {
|
|
6
|
+
:sm => "sm:max-w-sm",
|
|
7
|
+
:md => "sm:max-w-md",
|
|
8
|
+
:lg => "sm:max-w-lg",
|
|
9
|
+
:xl => "sm:max-w-xl",
|
|
10
|
+
"2xl" => "sm:max-w-2xl"
|
|
11
|
+
}[attributes[:max_width] || "2xl"]
|
|
12
|
+
@attributes = attributes.without(:name, :show, :max_width)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class NavLinkComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<a <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
</a>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
classes = attributes[:active] \
|
|
10
|
+
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 dark:border-indigo-600 text-sm font-medium leading-5 text-gray-900 dark:text-gray-100 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out' \
|
|
11
|
+
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out'
|
|
12
|
+
attributes[:class] = "#{classes}#{" #{attributes[:class]}" if attributes[:class]}"
|
|
13
|
+
@attributes = attributes.without(:active).map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class PrimaryButtonComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<button <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
</button>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
attributes[:type] = attributes[:type] || "submit"
|
|
10
|
+
attributes[:class] = "inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150#{" #{attributes[:class]}" if attributes[:class]}"
|
|
11
|
+
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class ResponsiveNavLinkComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<a <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
</a>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
classes = attributes[:active] \
|
|
10
|
+
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 dark:border-indigo-600 text-start text-base font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:outline-none focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300 transition duration-150 ease-in-out' \
|
|
11
|
+
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-gray-800 dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out'
|
|
12
|
+
attributes[:class] = "#{classes}#{" #{attributes[:class]}" if attributes[:class]}"
|
|
13
|
+
@attributes = attributes.without(:active).map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class SecondaryButtonComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<button <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
<%= content %>
|
|
5
|
+
</button>
|
|
6
|
+
ERB
|
|
7
|
+
|
|
8
|
+
def initialize(attributes = {})
|
|
9
|
+
attributes[:type] = attributes[:type] || "button"
|
|
10
|
+
attributes[:class] = "inline-flex items-center px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150#{" #{attributes[:class]}" if attributes[:class]}"
|
|
11
|
+
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class TextInputComponent < ViewComponent::Base
|
|
2
|
+
erb_template <<~ERB
|
|
3
|
+
<input <%= @disabled ? "disabled" : "" %> <%= sanitize @attributes.join(" ") %>>
|
|
4
|
+
ERB
|
|
5
|
+
|
|
6
|
+
def initialize(attributes = {})
|
|
7
|
+
@disabled = attributes[:disabled] || false
|
|
8
|
+
attributes[:class] = "border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm#{" #{attributes[:class]}" if attributes[:class]}"
|
|
9
|
+
@attributes = attributes.without(:disabled).map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
|
10
|
+
end
|
|
11
|
+
end
|