kaze 0.3.0 → 0.5.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 +17 -13
- data/lib/kaze/commands/installs_hotwire_stack.rb +6 -6
- data/lib/kaze/commands/installs_inertia_stacks.rb +22 -22
- data/lib/kaze/commands/version_command.rb +6 -0
- data/lib/kaze/version.rb +1 -1
- data/lib/kaze.rb +1 -3
- data/stubs/default/app/forms/auth/login_form.rb +1 -1
- data/stubs/default/app/forms/auth/new_password_form.rb +1 -1
- data/stubs/default/app/mailers/application_mailer.rb +4 -4
- data/stubs/default/app/mailers/user_mailer.rb +1 -1
- data/stubs/default/app/validators/current_password_validator.rb +1 -1
- data/stubs/default/app/validators/email_validator.rb +1 -1
- data/stubs/default/app/validators/lowercase_validator.rb +2 -2
- data/stubs/default/config/routes.rb +16 -16
- data/stubs/default/db/migrate/20240101000001_create_delayed_jobs.rb +1 -1
- data/stubs/hotwire/app/components/danger_button_component.rb +1 -1
- data/stubs/hotwire/app/components/dropdown_component.rb +7 -7
- data/stubs/hotwire/app/components/modal_component.rb +1 -1
- data/stubs/hotwire/app/components/primary_button_component.rb +1 -1
- data/stubs/hotwire/app/components/secondary_button_component.rb +1 -1
- data/stubs/hotwire/app/controllers/auth/authenticated_session_controller.rb +3 -3
- data/stubs/hotwire/app/controllers/auth/new_password_controller.rb +4 -4
- data/stubs/hotwire/app/controllers/auth/password_reset_link_controller.rb +4 -4
- data/stubs/hotwire/app/controllers/auth/registered_user_controller.rb +3 -3
- data/stubs/hotwire/app/controllers/password_controller.rb +2 -2
- data/stubs/hotwire/app/controllers/profile_controller.rb +5 -5
- data/stubs/hotwire/bin/vite +6 -6
- data/stubs/hotwire/config/importmap.rb +3 -3
- data/stubs/inertia-common/app/controllers/auth/authenticated_session_controller.rb +1 -1
- data/stubs/inertia-common/app/controllers/auth/new_password_controller.rb +2 -2
- data/stubs/inertia-common/app/controllers/auth/password_reset_link_controller.rb +2 -2
- data/stubs/inertia-common/app/controllers/auth/registered_user_controller.rb +1 -1
- data/stubs/inertia-common/app/controllers/concerns/verify_csrf_token.rb +4 -4
- data/stubs/inertia-common/app/controllers/dashboard_controller.rb +1 -1
- data/stubs/inertia-common/app/controllers/profile_controller.rb +2 -2
- data/stubs/inertia-common/app/controllers/welcome_controller.rb +1 -1
- data/stubs/inertia-common/bin/vite +6 -6
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d47e0df09c4dc843e721f9df107ffcf181cab7f3922233b9b82ca6ecd1eafa20
|
4
|
+
data.tar.gz: a932b205c852cf2825867f11b9a4d0c7f580a798be9b14c96b2745a705109105
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ab37093d08694cbdacd55fab7328c8c1c8042996605dffd16b48d709007377c5479c8a95085e611ff195961caee9b64815b13e9323134a981d81f11e776e3c2
|
7
|
+
data.tar.gz: beb37ead1dd42947264d72f58a93b113795a0361cf9979d7f5166273702b2c515c262a67be9be218f5dc185a0f9897367c34bc0fc3167d1076aa5483558a00b8
|
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
|
@@ -1,27 +1,27 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'bundler'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'open3'
|
4
|
+
require 'thor'
|
5
5
|
|
6
6
|
class Kaze::Commands::InstallCommand < Thor
|
7
7
|
include Kaze::Commands::InstallsHotwireStack
|
8
8
|
include Kaze::Commands::InstallsInertiaStacks
|
9
9
|
|
10
|
-
desc
|
11
|
-
def install(stack =
|
12
|
-
if stack ==
|
10
|
+
desc 'install [STACK]', 'Install the Kaze controllers and resources. Supported stacks: hotwire, react, vue.'
|
11
|
+
def install(stack = 'hotwire')
|
12
|
+
if stack == 'hotwire'
|
13
13
|
return install_hotwire_stack
|
14
14
|
end
|
15
15
|
|
16
|
-
if stack ==
|
16
|
+
if stack == 'react'
|
17
17
|
return install_inertia_react_stack
|
18
18
|
end
|
19
19
|
|
20
|
-
if stack ==
|
20
|
+
if stack == 'vue'
|
21
21
|
return install_inertia_vue_stack
|
22
22
|
end
|
23
23
|
|
24
|
-
say
|
24
|
+
say 'Invalid stack. Supported stacks are [hotwire], [react], [vue].', :red
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
@@ -53,9 +53,13 @@ class Kaze::Commands::InstallCommand < Thor
|
|
53
53
|
def install_migrations
|
54
54
|
ensure_directory_exists("#{Dir.pwd}/db/migrate")
|
55
55
|
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/default/db/migrate", "#{Dir.pwd}/db/migrate")
|
56
|
-
stdin, _ = Open3.capture3(
|
57
|
-
versions = stdin.gsub!(
|
58
|
-
|
56
|
+
stdin, _ = Open3.capture3('rails version')
|
57
|
+
versions = stdin.gsub!('Rails ', '').split('.')
|
58
|
+
railsVersion = [ versions[0], versions[1] ].join('.')
|
59
|
+
Dir.children("#{Dir.pwd}/db/migrate").each do |file|
|
60
|
+
path = "#{Dir.pwd}/db/migrate/#{file}"
|
61
|
+
File.write(path, File.read(path).gsub!(/ActiveRecord::Migration$/, "ActiveRecord::Migration[#{railsVersion}]"))
|
62
|
+
end
|
59
63
|
end
|
60
64
|
|
61
65
|
def ensure_directory_exists(path)
|
@@ -3,9 +3,9 @@ module Kaze::Commands::InstallsHotwireStack
|
|
3
3
|
|
4
4
|
def install_hotwire_stack
|
5
5
|
# Gems...
|
6
|
-
return unless remove_gems([
|
7
|
-
return unless install_gems([
|
8
|
-
return unless install_gems([
|
6
|
+
return unless remove_gems([ 'sprockets-rails', 'stimulus-rails' ])
|
7
|
+
return unless install_gems([ 'propshaft', 'view_component', 'tailwindcss-rails', 'turbo-rails', 'dotenv', 'bcrypt' ])
|
8
|
+
return unless install_gems([ 'hotwire-livereload' ], 'development')
|
9
9
|
|
10
10
|
# Controllers...
|
11
11
|
FileUtils.copy_entry("#{File.dirname(__FILE__)}/../../../stubs/hotwire/app/controllers", "#{Dir.pwd}/app/controllers")
|
@@ -54,9 +54,9 @@ module Kaze::Commands::InstallsHotwireStack
|
|
54
54
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/hotwire/config/tailwind.config.js", "#{Dir.pwd}/config/tailwind.config.js")
|
55
55
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/bin/dev", "#{Dir.pwd}/bin/dev")
|
56
56
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/hotwire/Procfile.dev", "#{Dir.pwd}/Procfile.dev")
|
57
|
-
run_command(
|
57
|
+
run_command('rails tailwindcss:build')
|
58
58
|
|
59
|
-
say
|
60
|
-
say
|
59
|
+
say ''
|
60
|
+
say 'Kaze scaffolding installed successfully.', :green
|
61
61
|
end
|
62
62
|
end
|
@@ -3,8 +3,8 @@ module Kaze::Commands::InstallsInertiaStacks
|
|
3
3
|
|
4
4
|
def install_inertia_react_stack
|
5
5
|
# Gems...
|
6
|
-
return unless remove_gems([
|
7
|
-
return unless install_gems([
|
6
|
+
return unless remove_gems([ 'sprockets-rails', 'turbo-rails', 'stimulus-rails' ])
|
7
|
+
return unless install_gems([ 'propshaft', 'tailwindcss-rails', 'inertia_rails', 'vite_rails', 'dotenv', 'bcrypt', 'js-routes' ])
|
8
8
|
|
9
9
|
# NPM Packages...
|
10
10
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-react-ts/package.json", "#{Dir.pwd}/package.json")
|
@@ -57,29 +57,29 @@ module Kaze::Commands::InstallsInertiaStacks
|
|
57
57
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/bin/dev", "#{Dir.pwd}/bin/dev")
|
58
58
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/bin/vite", "#{Dir.pwd}/bin/vite")
|
59
59
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/Procfile.dev", "#{Dir.pwd}/Procfile.dev")
|
60
|
-
run_command(
|
60
|
+
run_command('rails generate js_routes:middleware')
|
61
61
|
|
62
|
-
say
|
63
|
-
say
|
62
|
+
say ''
|
63
|
+
say 'Installing and building Node dependencies.', :magenta
|
64
64
|
|
65
65
|
if File.exist?("#{Dir.pwd}/pnpm-lock.yaml")
|
66
|
-
run_commands([
|
66
|
+
run_commands([ 'pnpm install', 'pnpm run build' ])
|
67
67
|
elsif File.exist?("#{Dir.pwd}/yarn.lock")
|
68
|
-
run_commands([
|
68
|
+
run_commands([ 'yarn install', 'yarn build' ])
|
69
69
|
elsif File.exist?("#{Dir.pwd}/bun.lockb")
|
70
|
-
run_commands([
|
70
|
+
run_commands([ 'bun install', 'bun run build' ])
|
71
71
|
else
|
72
|
-
run_commands([
|
72
|
+
run_commands([ 'npm install', 'npm run build' ])
|
73
73
|
end
|
74
74
|
|
75
|
-
say
|
76
|
-
say
|
75
|
+
say ''
|
76
|
+
say 'Kaze scaffolding installed successfully.', :green
|
77
77
|
end
|
78
78
|
|
79
79
|
def install_inertia_vue_stack
|
80
80
|
# Gems...
|
81
|
-
return unless remove_gems([
|
82
|
-
return unless install_gems([
|
81
|
+
return unless remove_gems([ 'sprockets-rails' ])
|
82
|
+
return unless install_gems([ 'propshaft', 'tailwindcss-rails', 'inertia_rails', 'vite_rails', 'dotenv', 'bcrypt', 'js-routes' ])
|
83
83
|
|
84
84
|
# NPM Packages...
|
85
85
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-vue-ts/package.json", "#{Dir.pwd}/package.json")
|
@@ -132,22 +132,22 @@ module Kaze::Commands::InstallsInertiaStacks
|
|
132
132
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/default/bin/dev", "#{Dir.pwd}/bin/dev")
|
133
133
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/bin/vite", "#{Dir.pwd}/bin/vite")
|
134
134
|
FileUtils.copy_file("#{File.dirname(__FILE__)}/../../../stubs/inertia-common/Procfile.dev", "#{Dir.pwd}/Procfile.dev")
|
135
|
-
run_command(
|
135
|
+
run_command('rails generate js_routes:middleware')
|
136
136
|
|
137
|
-
say
|
138
|
-
say
|
137
|
+
say ''
|
138
|
+
say 'Installing and building Node dependencies.', :magenta
|
139
139
|
|
140
140
|
if File.exist?("#{Dir.pwd}/pnpm-lock.yaml")
|
141
|
-
run_commands([
|
141
|
+
run_commands([ 'pnpm install', 'pnpm run build' ])
|
142
142
|
elsif File.exist?("#{Dir.pwd}/yarn.lock")
|
143
|
-
run_commands([
|
143
|
+
run_commands([ 'yarn install', 'yarn build' ])
|
144
144
|
elsif File.exist?("#{Dir.pwd}/bun.lockb")
|
145
|
-
run_commands([
|
145
|
+
run_commands([ 'bun install', 'bun run build' ])
|
146
146
|
else
|
147
|
-
run_commands([
|
147
|
+
run_commands([ 'npm install', 'npm run build' ])
|
148
148
|
end
|
149
149
|
|
150
|
-
say
|
151
|
-
say
|
150
|
+
say ''
|
151
|
+
say 'Kaze scaffolding installed successfully.', :green
|
152
152
|
end
|
153
153
|
end
|
data/lib/kaze/version.rb
CHANGED
data/lib/kaze.rb
CHANGED
@@ -10,7 +10,7 @@ class Auth::NewPasswordForm < ApplicationForm
|
|
10
10
|
user = User.find_by_token_for(:password_reset, token)
|
11
11
|
|
12
12
|
if user.nil?
|
13
|
-
errors.add(:password, message:
|
13
|
+
errors.add(:password, message: 'This password reset token is invalid.')
|
14
14
|
return false
|
15
15
|
end
|
16
16
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
class ApplicationMailer < ActionMailer::Base
|
2
2
|
default from: email_address_with_name(
|
3
|
-
ENV.fetch(
|
4
|
-
ENV.fetch(
|
3
|
+
ENV.fetch('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
4
|
+
ENV.fetch('MAIL_FROM_NAME', 'Example')
|
5
5
|
)
|
6
|
-
layout
|
6
|
+
layout 'mailer'
|
7
7
|
|
8
8
|
def default_url_options
|
9
|
-
{ host: ENV.fetch(
|
9
|
+
{ host: ENV.fetch('APP_URL', 'http://localhost') }
|
10
10
|
end
|
11
11
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class CurrentPasswordValidator < ActiveModel::EachValidator
|
2
2
|
def validate_each(record, attribute, value)
|
3
|
-
record.errors.add attribute,
|
3
|
+
record.errors.add attribute, 'The password is incorrect.' unless Current.user&.authenticate(value)
|
4
4
|
end
|
5
5
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class EmailValidator < ActiveModel::EachValidator
|
2
2
|
def validate_each(record, attribute, value)
|
3
3
|
unless URI::MailTo::EMAIL_REGEXP.match?(value)
|
4
|
-
record.errors.add attribute, (options[:message] ||
|
4
|
+
record.errors.add attribute, (options[:message] || 'is not an email')
|
5
5
|
end
|
6
6
|
end
|
7
7
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class LowercaseValidator < ActiveModel::EachValidator
|
2
2
|
def validate_each(record, attribute, value)
|
3
|
-
value =
|
4
|
-
record.errors.add attribute, (options[:message] ||
|
3
|
+
value = '' if value.nil?
|
4
|
+
record.errors.add attribute, (options[:message] || 'must be lowercase') unless value == value.downcase
|
5
5
|
end
|
6
6
|
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
|
-
get
|
2
|
+
get 'up' => 'rails/health#show', as: :rails_health_check
|
3
3
|
|
4
|
-
root
|
4
|
+
root 'welcome#index'
|
5
5
|
|
6
|
-
get
|
7
|
-
post
|
6
|
+
get 'register', to: 'auth/registered_user#new', as: :register
|
7
|
+
post 'register', to: 'auth/registered_user#create'
|
8
8
|
|
9
|
-
get
|
10
|
-
post
|
9
|
+
get 'login', to: 'auth/authenticated_session#new', as: :login
|
10
|
+
post 'login', to: 'auth/authenticated_session#create'
|
11
11
|
|
12
|
-
get
|
13
|
-
post
|
12
|
+
get 'forgot-password', to: 'auth/password_reset_link#new', as: :password_request
|
13
|
+
post 'forgot-password', to: 'auth/password_reset_link#create', as: :password_email
|
14
14
|
|
15
|
-
get
|
16
|
-
post
|
15
|
+
get 'reset-password/:token', to: 'auth/new_password#new', as: :password_reset
|
16
|
+
post 'reset-password', to: 'auth/new_password#create', as: :password_store
|
17
17
|
|
18
|
-
post
|
18
|
+
post 'logout', to: 'auth/authenticated_session#destroy', as: :logout
|
19
19
|
|
20
|
-
get
|
20
|
+
get 'dashboard', to: 'dashboard#index', as: :dashboard
|
21
21
|
|
22
|
-
get
|
23
|
-
patch
|
24
|
-
delete
|
22
|
+
get 'profile', to: 'profile#edit', as: :profile_edit
|
23
|
+
patch 'profile', to: 'profile#update', as: :profile_update
|
24
|
+
delete 'profile', to: 'profile#destroy', as: :profile_destroy
|
25
25
|
|
26
|
-
put
|
26
|
+
put 'password', to: 'password#update', as: :password_update
|
27
27
|
end
|
@@ -13,7 +13,7 @@ class CreateDelayedJobs < ActiveRecord::Migration
|
|
13
13
|
table.timestamps null: true
|
14
14
|
end
|
15
15
|
|
16
|
-
add_index :delayed_jobs, [ :priority, :run_at ], name:
|
16
|
+
add_index :delayed_jobs, [ :priority, :run_at ], name: 'delayed_jobs_priority'
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.down
|
@@ -6,7 +6,7 @@ class DangerButtonComponent < ViewComponent::Base
|
|
6
6
|
ERB
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
|
-
attributes[:type] = attributes[:type] ||
|
9
|
+
attributes[:type] = attributes[:type] || 'submit'
|
10
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
11
|
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
12
12
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
class DropdownComponent < ViewComponent::Base
|
2
2
|
renders_one :trigger
|
3
3
|
|
4
|
-
def initialize(align:
|
5
|
-
if align ==
|
6
|
-
@alignment_classes =
|
7
|
-
elsif align ==
|
8
|
-
@alignment_classes =
|
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
9
|
else
|
10
|
-
@alignment_classes =
|
10
|
+
@alignment_classes = 'ltr:origin-top-right rtl:origin-top-left end-0'
|
11
11
|
end
|
12
|
-
@width = width ==
|
12
|
+
@width = width == '48' ? 'w-48' : width
|
13
13
|
@content_classes = content_classes
|
14
14
|
end
|
15
15
|
end
|
@@ -7,7 +7,7 @@ class ModalComponent < ViewComponent::Base
|
|
7
7
|
:md => 'sm:max-w-md',
|
8
8
|
:lg => 'sm:max-w-lg',
|
9
9
|
:xl => 'sm:max-w-xl',
|
10
|
-
'2xl' => 'sm:max-w-2xl'
|
10
|
+
'2xl' => 'sm:max-w-2xl'
|
11
11
|
}[attributes[:max_width] || '2xl']
|
12
12
|
@attributes = attributes.without(:name, :show, :max_width)
|
13
13
|
end
|
@@ -6,7 +6,7 @@ class PrimaryButtonComponent < ViewComponent::Base
|
|
6
6
|
ERB
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
|
-
attributes[:type] = attributes[:type] ||
|
9
|
+
attributes[:type] = attributes[:type] || 'submit'
|
10
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
11
|
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
12
12
|
end
|
@@ -6,7 +6,7 @@ class SecondaryButtonComponent < ViewComponent::Base
|
|
6
6
|
ERB
|
7
7
|
|
8
8
|
def initialize(attributes = {})
|
9
|
-
attributes[:type] = attributes[:type] ||
|
9
|
+
attributes[:type] = attributes[:type] || 'button'
|
10
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
11
|
@attributes = attributes.map { |key, attribute| "#{key}=\"#{attribute}\"" }
|
12
12
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
class Auth::AuthenticatedSessionController < ApplicationController
|
2
2
|
skip_authentication only: %i[new create]
|
3
3
|
|
4
|
-
layout
|
4
|
+
layout 'guest'
|
5
5
|
|
6
6
|
def new
|
7
7
|
@form = Auth::LoginForm.new
|
8
8
|
|
9
|
-
render
|
9
|
+
render 'auth/login'
|
10
10
|
end
|
11
11
|
|
12
12
|
def create
|
@@ -14,7 +14,7 @@ class Auth::AuthenticatedSessionController < ApplicationController
|
|
14
14
|
|
15
15
|
user = @form.authenticate
|
16
16
|
|
17
|
-
return render
|
17
|
+
return render 'auth/login', status: :unprocessable_entity if user.nil?
|
18
18
|
|
19
19
|
login user
|
20
20
|
|
@@ -1,19 +1,19 @@
|
|
1
1
|
class Auth::NewPasswordController < ApplicationController
|
2
2
|
skip_authentication
|
3
3
|
|
4
|
-
layout
|
4
|
+
layout 'guest'
|
5
5
|
|
6
6
|
def new
|
7
7
|
@form = Auth::NewPasswordForm.new params.permit(:token)
|
8
8
|
|
9
|
-
render
|
9
|
+
render 'auth/reset_password'
|
10
10
|
end
|
11
11
|
|
12
12
|
def create
|
13
13
|
@form = Auth::NewPasswordForm.new params.permit(:token, :password, :password_confirmation)
|
14
14
|
|
15
|
-
return redirect_to login_path, flash: { status:
|
15
|
+
return redirect_to login_path, flash: { status: 'Your password has been reset.' } if @form.reset?
|
16
16
|
|
17
|
-
render
|
17
|
+
render 'auth/reset_password', status: :unprocessable_entity
|
18
18
|
end
|
19
19
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
class Auth::PasswordResetLinkController < ApplicationController
|
2
2
|
skip_authentication
|
3
3
|
|
4
|
-
layout
|
4
|
+
layout 'guest'
|
5
5
|
|
6
6
|
def new
|
7
7
|
@form = Auth::SendPasswordResetLinkForm.new
|
8
8
|
|
9
|
-
render
|
9
|
+
render 'auth/forgot_password'
|
10
10
|
end
|
11
11
|
|
12
12
|
def create
|
13
13
|
@form = Auth::SendPasswordResetLinkForm.new params.permit(:email)
|
14
14
|
|
15
|
-
return redirect_back_or_to password_request_path, flash: { status:
|
15
|
+
return redirect_back_or_to password_request_path, flash: { status: 'We have emailed your password reset link.' } if @form.send_reset_link?
|
16
16
|
|
17
|
-
render
|
17
|
+
render 'auth/forgot_password', status: :unprocessable_entity
|
18
18
|
end
|
19
19
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
class Auth::RegisteredUserController < ApplicationController
|
2
2
|
skip_authentication
|
3
3
|
|
4
|
-
layout
|
4
|
+
layout 'guest'
|
5
5
|
|
6
6
|
def new
|
7
7
|
@form = Auth::RegisterForm.new
|
8
8
|
|
9
|
-
render
|
9
|
+
render 'auth/register'
|
10
10
|
end
|
11
11
|
|
12
12
|
def create
|
13
13
|
@form = Auth::RegisterForm.new params.permit(:name, :email, :password, :password_confirmation)
|
14
14
|
|
15
|
-
return render
|
15
|
+
return render 'auth/register', status: :unprocessable_entity if @form.invalid?
|
16
16
|
|
17
17
|
user = User.create(name: @form.name, email: @form.email, password: @form.password)
|
18
18
|
|
@@ -2,10 +2,10 @@ class PasswordController < ApplicationController
|
|
2
2
|
def update
|
3
3
|
@update_password_form = UpdatePasswordForm.new params.permit(:current_password, :password, :password_confirmation)
|
4
4
|
|
5
|
-
return render partial:
|
5
|
+
return render partial: 'profile/partials/update_password_form', status: :unprocessable_entity if @update_password_form.invalid?
|
6
6
|
|
7
7
|
Current.user.update(password: @update_password_form.password)
|
8
8
|
|
9
|
-
redirect_back_or_to profile_edit_path, flash: { status:
|
9
|
+
redirect_back_or_to profile_edit_path, flash: { status: 'password-updated' }
|
10
10
|
end
|
11
11
|
end
|
@@ -4,23 +4,23 @@ class ProfileController < ApplicationController
|
|
4
4
|
@update_password_form = UpdatePasswordForm.new
|
5
5
|
@delete_user_form = DeleteUserForm.new
|
6
6
|
|
7
|
-
render
|
7
|
+
render 'profile/edit'
|
8
8
|
end
|
9
9
|
|
10
10
|
def update
|
11
11
|
@update_profile_information_form = UpdateProfileInformationForm.new params.permit(:name, :email)
|
12
12
|
|
13
|
-
return render partial:
|
13
|
+
return render partial: 'profile/partials/update_profile_information_form', status: :unprocessable_entity if @update_profile_information_form.invalid?
|
14
14
|
|
15
15
|
Current.user.update(name: @update_profile_information_form.name, email: @update_profile_information_form.email)
|
16
16
|
|
17
|
-
redirect_to profile_edit_path, flash: { status:
|
17
|
+
redirect_to profile_edit_path, flash: { status: 'profile-updated' }
|
18
18
|
end
|
19
19
|
|
20
20
|
def destroy
|
21
21
|
@delete_user_form = DeleteUserForm.new params.permit(:password)
|
22
22
|
|
23
|
-
return render partial:
|
23
|
+
return render partial: 'profile/partials/delete_user_form', status: :unprocessable_entity if @delete_user_form.invalid?
|
24
24
|
|
25
25
|
user = Current.user
|
26
26
|
|
@@ -28,6 +28,6 @@ class ProfileController < ApplicationController
|
|
28
28
|
|
29
29
|
user.delete
|
30
30
|
|
31
|
-
redirect_to
|
31
|
+
redirect_to '/'
|
32
32
|
end
|
33
33
|
end
|
data/stubs/hotwire/bin/vite
CHANGED
@@ -8,12 +8,12 @@
|
|
8
8
|
# this file is here to facilitate running it.
|
9
9
|
#
|
10
10
|
|
11
|
-
ENV[
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
12
12
|
|
13
|
-
bundle_binstub = File.expand_path(
|
13
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
14
14
|
|
15
15
|
if File.file?(bundle_binstub)
|
16
|
-
if File.read(bundle_binstub, 300).include?(
|
16
|
+
if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
|
17
17
|
load(bundle_binstub)
|
18
18
|
else
|
19
19
|
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
@@ -21,7 +21,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
require
|
25
|
-
require
|
24
|
+
require 'rubygems'
|
25
|
+
require 'bundler/setup'
|
26
26
|
|
27
|
-
load Gem.bin_path(
|
27
|
+
load Gem.bin_path('vite_ruby', 'vite')
|
@@ -1,3 +1,3 @@
|
|
1
|
-
pin
|
2
|
-
pin
|
3
|
-
pin
|
1
|
+
pin 'application'
|
2
|
+
pin '@hotwired/turbo-rails', to: 'turbo.min.js'
|
3
|
+
pin 'alpinejs'
|
@@ -2,7 +2,7 @@ class Auth::NewPasswordController < ApplicationController
|
|
2
2
|
skip_authentication
|
3
3
|
|
4
4
|
def new
|
5
|
-
render inertia:
|
5
|
+
render inertia: 'Auth/ResetPassword', props: {
|
6
6
|
token: params[:token]
|
7
7
|
}
|
8
8
|
end
|
@@ -10,7 +10,7 @@ class Auth::NewPasswordController < ApplicationController
|
|
10
10
|
def create
|
11
11
|
form = Auth::NewPasswordForm.new params.permit(:token, :password, :password_confirmation)
|
12
12
|
|
13
|
-
return redirect_to login_path, flash: { status:
|
13
|
+
return redirect_to login_path, flash: { status: 'Your password has been reset.' } if form.reset?
|
14
14
|
|
15
15
|
redirect_back_or_to password_reset_path(token: form.token),
|
16
16
|
inertia: { errors: form.error_messages }
|
@@ -2,7 +2,7 @@ class Auth::PasswordResetLinkController < ApplicationController
|
|
2
2
|
skip_authentication
|
3
3
|
|
4
4
|
def new
|
5
|
-
render inertia:
|
5
|
+
render inertia: 'Auth/ForgotPassword', props: {
|
6
6
|
status: flash[:status]
|
7
7
|
}
|
8
8
|
end
|
@@ -12,6 +12,6 @@ class Auth::PasswordResetLinkController < ApplicationController
|
|
12
12
|
|
13
13
|
return redirect_back_or_to password_request_path, inertia: { errors: form.error_messages } unless form.send_reset_link?
|
14
14
|
|
15
|
-
redirect_back_or_to password_request_path, flash: { status:
|
15
|
+
redirect_back_or_to password_request_path, flash: { status: 'We have emailed your password reset link.' }
|
16
16
|
end
|
17
17
|
end
|
@@ -5,20 +5,20 @@ module VerifyCsrfToken
|
|
5
5
|
before_action :set_csrf_cookie
|
6
6
|
|
7
7
|
rescue_from ActionController::InvalidAuthenticityToken do
|
8
|
-
redirect_back fallback_location:
|
8
|
+
redirect_back fallback_location: '/', notice: 'The page expired, please try again.'
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def request_authenticity_tokens
|
13
|
-
super << request.headers[
|
13
|
+
super << request.headers['HTTP_X_XSRF_TOKEN']
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def set_csrf_cookie
|
19
|
-
cookies[
|
19
|
+
cookies['XSRF-TOKEN'] = {
|
20
20
|
value: form_authenticity_token,
|
21
|
-
same_site:
|
21
|
+
same_site: 'Strict'
|
22
22
|
}
|
23
23
|
end
|
24
24
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class ProfileController < ApplicationController
|
2
2
|
def edit
|
3
|
-
render inertia:
|
3
|
+
render inertia: 'Profile/Edit', props: {
|
4
4
|
status: session[:status]
|
5
5
|
}
|
6
6
|
end
|
@@ -26,6 +26,6 @@ class ProfileController < ApplicationController
|
|
26
26
|
|
27
27
|
user.delete
|
28
28
|
|
29
|
-
redirect_to
|
29
|
+
redirect_to '/'
|
30
30
|
end
|
31
31
|
end
|
@@ -8,12 +8,12 @@
|
|
8
8
|
# this file is here to facilitate running it.
|
9
9
|
#
|
10
10
|
|
11
|
-
ENV[
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
12
12
|
|
13
|
-
bundle_binstub = File.expand_path(
|
13
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
14
14
|
|
15
15
|
if File.file?(bundle_binstub)
|
16
|
-
if File.read(bundle_binstub, 300).include?(
|
16
|
+
if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
|
17
17
|
load(bundle_binstub)
|
18
18
|
else
|
19
19
|
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
@@ -21,7 +21,7 @@ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
require
|
25
|
-
require
|
24
|
+
require 'rubygems'
|
25
|
+
require 'bundler/setup'
|
26
26
|
|
27
|
-
load Gem.bin_path(
|
27
|
+
load Gem.bin_path('vite_ruby', 'vite')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kaze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cuong Giang
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/kaze/commands/install_command.rb
|
69
69
|
- lib/kaze/commands/installs_hotwire_stack.rb
|
70
70
|
- lib/kaze/commands/installs_inertia_stacks.rb
|
71
|
+
- lib/kaze/commands/version_command.rb
|
71
72
|
- lib/kaze/version.rb
|
72
73
|
- stubs/default/app/assets/stylesheets/application.css
|
73
74
|
- stubs/default/app/assets/stylesheets/application.tailwind.css
|