kaze 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|