kaze 0.4.0 → 0.6.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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kaze/commands/install_command.rb +25 -13
  3. data/lib/kaze/commands/installs_hotwire_stack.rb +11 -8
  4. data/lib/kaze/commands/installs_inertia_stacks.rb +34 -24
  5. data/lib/kaze/commands/version_command.rb +6 -0
  6. data/lib/kaze/version.rb +1 -1
  7. data/lib/kaze.rb +1 -3
  8. data/stubs/default/app/forms/auth/login_form.rb +2 -8
  9. data/stubs/default/app/forms/auth/new_password_form.rb +1 -1
  10. data/stubs/default/app/forms/update_profile_information_form.rb +1 -1
  11. data/stubs/default/app/mailers/application_mailer.rb +4 -4
  12. data/stubs/default/app/mailers/user_mailer.rb +1 -1
  13. data/stubs/default/app/models/auth.rb +57 -0
  14. data/stubs/default/app/models/current.rb +1 -1
  15. data/stubs/default/app/validators/current_password_validator.rb +1 -1
  16. data/stubs/default/app/validators/email_validator.rb +1 -1
  17. data/stubs/default/app/validators/lowercase_validator.rb +2 -2
  18. data/stubs/default/app/views/layouts/mailer.html.erb +367 -372
  19. data/stubs/default/app/views/layouts/mailer.text.erb +1 -4
  20. data/stubs/default/app/views/user_mailer/reset_password.html.erb +21 -26
  21. data/stubs/default/config/routes.rb +16 -16
  22. data/stubs/default/db/migrate/20240101000001_create_delayed_jobs.rb +1 -1
  23. data/stubs/default/test/factories/users.rb +7 -0
  24. data/stubs/default/test/integration/auth/authentication_test.rb +43 -0
  25. data/stubs/default/test/integration/auth/password_reset_test.rb +41 -0
  26. data/stubs/default/test/integration/auth/registration_test.rb +21 -0
  27. data/stubs/default/test/integration/password_update_test.rb +28 -0
  28. data/stubs/default/test/integration/profile_test.rb +51 -0
  29. data/stubs/default/test/test_helper.rb +38 -0
  30. data/stubs/hotwire/app/components/danger_button_component.rb +1 -1
  31. data/stubs/hotwire/app/components/dropdown_component.html.erb +17 -18
  32. data/stubs/hotwire/app/components/dropdown_component.rb +7 -7
  33. data/stubs/hotwire/app/components/modal_component.html.erb +55 -59
  34. data/stubs/hotwire/app/components/modal_component.rb +6 -6
  35. data/stubs/hotwire/app/components/primary_button_component.rb +1 -1
  36. data/stubs/hotwire/app/components/secondary_button_component.rb +1 -1
  37. data/stubs/hotwire/app/controllers/application_controller.rb +1 -0
  38. data/stubs/hotwire/app/controllers/auth/authenticated_session_controller.rb +12 -9
  39. data/stubs/hotwire/app/controllers/auth/new_password_controller.rb +7 -5
  40. data/stubs/hotwire/app/controllers/auth/password_reset_link_controller.rb +7 -5
  41. data/stubs/hotwire/app/controllers/auth/registered_user_controller.rb +7 -5
  42. data/stubs/hotwire/app/controllers/concerns/authenticate.rb +5 -20
  43. data/stubs/hotwire/app/controllers/concerns/redirect_if_authenticated.rb +19 -0
  44. data/stubs/hotwire/app/controllers/concerns/set_current_auth.rb +9 -0
  45. data/stubs/hotwire/app/controllers/password_controller.rb +3 -3
  46. data/stubs/hotwire/app/controllers/profile_controller.rb +11 -9
  47. data/stubs/hotwire/app/controllers/welcome_controller.rb +1 -1
  48. data/stubs/hotwire/app/javascript/application.js +3 -3
  49. data/stubs/hotwire/app/views/auth/forgot_password.html.erb +12 -17
  50. data/stubs/hotwire/app/views/auth/login.html.erb +0 -9
  51. data/stubs/hotwire/app/views/auth/register.html.erb +0 -13
  52. data/stubs/hotwire/app/views/auth/reset_password.html.erb +0 -7
  53. data/stubs/hotwire/app/views/dashboard/index.html.erb +9 -10
  54. data/stubs/hotwire/app/views/layouts/_navigation.html.erb +77 -87
  55. data/stubs/hotwire/app/views/layouts/application.html.erb +0 -9
  56. data/stubs/hotwire/app/views/layouts/guest.html.erb +0 -6
  57. data/stubs/hotwire/app/views/profile/edit.html.erb +19 -22
  58. data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +32 -42
  59. data/stubs/hotwire/app/views/profile/partials/_update_password_form.html.erb +42 -55
  60. data/stubs/hotwire/app/views/profile/partials/_update_profile_information_form.html.erb +36 -46
  61. data/stubs/hotwire/app/views/welcome/index.html.erb +34 -46
  62. data/stubs/hotwire/config/importmap.rb +3 -3
  63. data/stubs/hotwire/config/tailwind.config.js +2 -2
  64. data/stubs/inertia-common/app/controllers/application_controller.rb +1 -0
  65. data/stubs/inertia-common/app/controllers/auth/authenticated_session_controller.rb +11 -8
  66. data/stubs/inertia-common/app/controllers/auth/new_password_controller.rb +5 -3
  67. data/stubs/inertia-common/app/controllers/auth/password_reset_link_controller.rb +5 -3
  68. data/stubs/inertia-common/app/controllers/auth/registered_user_controller.rb +5 -3
  69. data/stubs/inertia-common/app/controllers/concerns/authenticate.rb +5 -20
  70. data/stubs/inertia-common/app/controllers/concerns/handle_inertia_requests.rb +1 -1
  71. data/stubs/inertia-common/app/controllers/concerns/redirect_if_authenticated.rb +19 -0
  72. data/stubs/inertia-common/app/controllers/concerns/set_current_auth.rb +9 -0
  73. data/stubs/inertia-common/app/controllers/concerns/verify_csrf_token.rb +4 -4
  74. data/stubs/inertia-common/app/controllers/dashboard_controller.rb +1 -1
  75. data/stubs/inertia-common/app/controllers/password_controller.rb +1 -1
  76. data/stubs/inertia-common/app/controllers/profile_controller.rb +7 -5
  77. data/stubs/inertia-common/app/controllers/welcome_controller.rb +2 -2
  78. data/stubs/inertia-common/bin/vite +6 -6
  79. data/stubs/inertia-common/test/integration/password_update_test.rb +28 -0
  80. data/stubs/inertia-common/test/integration/profile_test.rb +51 -0
  81. data/stubs/inertia-react-ts/app/javascript/Components/ApplicationLogo.tsx +13 -9
  82. data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +15 -12
  83. data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +20 -15
  84. data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +119 -87
  85. data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +14 -7
  86. data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +18 -7
  87. data/stubs/inertia-react-ts/app/javascript/Components/Modal.tsx +60 -60
  88. data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +21 -16
  89. data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +20 -15
  90. data/stubs/inertia-react-ts/app/javascript/Components/ResponsiveNavLink.tsx +19 -14
  91. data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +22 -16
  92. data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +35 -24
  93. data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +157 -117
  94. data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +15 -15
  95. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +52 -49
  96. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +90 -82
  97. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +118 -115
  98. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +63 -60
  99. data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +23 -17
  100. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +31 -27
  101. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +109 -99
  102. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx +121 -113
  103. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx +76 -69
  104. data/stubs/inertia-react-ts/app/javascript/Pages/Welcome.tsx +87 -63
  105. data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +32 -25
  106. data/stubs/inertia-react-ts/app/views/layouts/application.html.erb +0 -4
  107. data/stubs/inertia-react-ts/config/tailwind.config.js +2 -2
  108. data/stubs/inertia-react-ts/vite.config.ts +2 -5
  109. data/stubs/inertia-vue-ts/app/javascript/Components/ApplicationLogo.vue +10 -6
  110. data/stubs/inertia-vue-ts/app/javascript/Components/Checkbox.vue +18 -18
  111. data/stubs/inertia-vue-ts/app/javascript/Components/DangerButton.vue +5 -5
  112. data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +60 -57
  113. data/stubs/inertia-vue-ts/app/javascript/Components/DropdownLink.vue +9 -9
  114. data/stubs/inertia-vue-ts/app/javascript/Components/InputError.vue +7 -7
  115. data/stubs/inertia-vue-ts/app/javascript/Components/InputLabel.vue +6 -6
  116. data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +84 -74
  117. data/stubs/inertia-vue-ts/app/javascript/Components/NavLink.vue +12 -12
  118. data/stubs/inertia-vue-ts/app/javascript/Components/PrimaryButton.vue +5 -5
  119. data/stubs/inertia-vue-ts/app/javascript/Components/ResponsiveNavLink.vue +12 -12
  120. data/stubs/inertia-vue-ts/app/javascript/Components/SecondaryButton.vue +13 -13
  121. data/stubs/inertia-vue-ts/app/javascript/Components/TextInput.vue +13 -13
  122. data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +168 -136
  123. data/stubs/inertia-vue-ts/app/javascript/Layouts/GuestLayout.vue +15 -13
  124. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +56 -49
  125. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +78 -72
  126. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +101 -97
  127. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +71 -68
  128. data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +22 -14
  129. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +34 -30
  130. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +87 -83
  131. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue +105 -98
  132. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue +69 -59
  133. data/stubs/inertia-vue-ts/app/javascript/Pages/Welcome.vue +74 -47
  134. data/stubs/inertia-vue-ts/app/views/layouts/application.html.erb +0 -4
  135. data/stubs/inertia-vue-ts/config/tailwind.config.js +2 -2
  136. data/stubs/inertia-vue-ts/vite.config.ts +2 -5
  137. metadata +19 -6
  138. data/stubs/hotwire/bin/vite +0 -27
  139. data/stubs/inertia-common/Procfile.dev +0 -3
  140. /data/stubs/{hotwire → default}/Procfile.dev +0 -0
  141. /data/stubs/hotwire/app/javascript/{alpinejs.js → alpinejs.stub} +0 -0
@@ -1,29 +1,32 @@
1
1
  class Auth::AuthenticatedSessionController < ApplicationController
2
- skip_authentication only: %i[new create]
2
+ include RedirectIfAuthenticated
3
3
 
4
- layout "guest"
4
+ skip_authenticate only: %i[new create]
5
+ skip_redirect_if_authenticated only: %i[destroy]
6
+
7
+ layout 'guest'
5
8
 
6
9
  def new
7
10
  @form = Auth::LoginForm.new
8
11
 
9
- render "auth/login"
12
+ render 'auth/login'
10
13
  end
11
14
 
12
15
  def create
13
16
  @form = Auth::LoginForm.new params.permit(:email, :password)
14
17
 
15
- user = @form.authenticate
16
-
17
- return render "auth/login", status: :unprocessable_entity if user.nil?
18
+ @form.authenticate
18
19
 
19
- login user
20
+ return render 'auth/login', status: :unprocessable_entity if Current.auth.user.nil?
20
21
 
21
22
  redirect_to dashboard_path
22
23
  end
23
24
 
24
25
  def destroy
25
- logout
26
+ Current.auth.logout
27
+
28
+ reset_session
26
29
 
27
- redirect_to login_path
30
+ redirect_to '/'
28
31
  end
29
32
  end
@@ -1,19 +1,21 @@
1
1
  class Auth::NewPasswordController < ApplicationController
2
- skip_authentication
2
+ include RedirectIfAuthenticated
3
3
 
4
- layout "guest"
4
+ skip_authenticate
5
+
6
+ layout 'guest'
5
7
 
6
8
  def new
7
9
  @form = Auth::NewPasswordForm.new params.permit(:token)
8
10
 
9
- render "auth/reset_password"
11
+ render 'auth/reset_password'
10
12
  end
11
13
 
12
14
  def create
13
15
  @form = Auth::NewPasswordForm.new params.permit(:token, :password, :password_confirmation)
14
16
 
15
- return redirect_to login_path, flash: { status: "Your password has been reset." } if @form.reset?
17
+ return redirect_to login_path, flash: { status: 'Your password has been reset.' } if @form.reset?
16
18
 
17
- render "auth/reset_password", status: :unprocessable_entity
19
+ render 'auth/reset_password', status: :unprocessable_entity
18
20
  end
19
21
  end
@@ -1,19 +1,21 @@
1
1
  class Auth::PasswordResetLinkController < ApplicationController
2
- skip_authentication
2
+ include RedirectIfAuthenticated
3
3
 
4
- layout "guest"
4
+ skip_authenticate
5
+
6
+ layout 'guest'
5
7
 
6
8
  def new
7
9
  @form = Auth::SendPasswordResetLinkForm.new
8
10
 
9
- render "auth/forgot_password"
11
+ render 'auth/forgot_password'
10
12
  end
11
13
 
12
14
  def create
13
15
  @form = Auth::SendPasswordResetLinkForm.new params.permit(:email)
14
16
 
15
- return redirect_back_or_to password_request_path, flash: { status: "We have emailed your password reset link." } if @form.send_reset_link?
17
+ return redirect_back_or_to password_request_path, flash: { status: 'We have emailed your password reset link.' } if @form.send_reset_link?
16
18
 
17
- render "auth/forgot_password", status: :unprocessable_entity
19
+ render 'auth/forgot_password', status: :unprocessable_entity
18
20
  end
19
21
  end
@@ -1,22 +1,24 @@
1
1
  class Auth::RegisteredUserController < ApplicationController
2
- skip_authentication
2
+ include RedirectIfAuthenticated
3
3
 
4
- layout "guest"
4
+ skip_authenticate
5
+
6
+ layout 'guest'
5
7
 
6
8
  def new
7
9
  @form = Auth::RegisterForm.new
8
10
 
9
- render "auth/register"
11
+ render 'auth/register'
10
12
  end
11
13
 
12
14
  def create
13
15
  @form = Auth::RegisterForm.new params.permit(:name, :email, :password, :password_confirmation)
14
16
 
15
- return render "auth/register", status: :unprocessable_entity if @form.invalid?
17
+ return render 'auth/register', status: :unprocessable_entity if @form.invalid?
16
18
 
17
19
  user = User.create(name: @form.name, email: @form.email, password: @form.password)
18
20
 
19
- login user
21
+ Current.auth.login user
20
22
 
21
23
  redirect_to dashboard_path
22
24
  end
@@ -2,33 +2,18 @@ module Authenticate
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- before_action :authenticate_user!
5
+ before_action :authenticate!
6
6
  end
7
7
 
8
8
  class_methods do
9
- def skip_authentication(**options)
10
- skip_before_action :authenticate_user!, **options
9
+ def skip_authenticate(**options)
10
+ skip_before_action :authenticate!, **options
11
11
  end
12
12
  end
13
13
 
14
14
  private
15
15
 
16
- def authenticate_user!
17
- if user = User.find_by(id: session[:user_id])
18
- Current.user = user
19
- else
20
- redirect_to login_path
21
- end
22
- end
23
-
24
- def login(user)
25
- Current.user = user
26
- reset_session
27
- session[:user_id] = user.id
28
- end
29
-
30
- def logout
31
- Current.user = nil
32
- reset_session
16
+ def authenticate!
17
+ redirect_to login_path unless Current.auth.check?
33
18
  end
34
19
  end
@@ -0,0 +1,19 @@
1
+ module RedirectIfAuthenticated
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :redirect_if_authenticated!
6
+ end
7
+
8
+ class_methods do
9
+ def skip_redirect_if_authenticated(**options)
10
+ skip_before_action :redirect_if_authenticated!, **options
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def redirect_if_authenticated!
17
+ redirect_to dashboard_path if Current.auth.check?
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module SetCurrentAuth
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action do
6
+ Current.auth = Auth.new('web', session)
7
+ end
8
+ end
9
+ end
@@ -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: "profile/partials/update_password_form", status: :unprocessable_entity if @update_password_form.invalid?
5
+ return render partial: 'profile/partials/update_password_form', status: :unprocessable_entity if @update_password_form.invalid?
6
6
 
7
- Current.user.update(password: @update_password_form.password)
7
+ Current.auth.user.update(password: @update_password_form.password)
8
8
 
9
- redirect_back_or_to profile_edit_path, flash: { status: "password-updated" }
9
+ redirect_back_or_to profile_edit_path, flash: { status: 'password-updated' }
10
10
  end
11
11
  end
@@ -1,33 +1,35 @@
1
1
  class ProfileController < ApplicationController
2
2
  def edit
3
- @update_profile_information_form = UpdateProfileInformationForm.new(name: Current.user.name, email: Current.user.email)
3
+ @update_profile_information_form = UpdateProfileInformationForm.new(name: Current.auth.user.name, email: Current.auth.user.email)
4
4
  @update_password_form = UpdatePasswordForm.new
5
5
  @delete_user_form = DeleteUserForm.new
6
6
 
7
- render "profile/edit"
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: "profile/partials/update_profile_information_form", status: :unprocessable_entity if @update_profile_information_form.invalid?
13
+ return render partial: 'profile/partials/update_profile_information_form', status: :unprocessable_entity if @update_profile_information_form.invalid?
14
14
 
15
- Current.user.update(name: @update_profile_information_form.name, email: @update_profile_information_form.email)
15
+ Current.auth.user.update(name: @update_profile_information_form.name, email: @update_profile_information_form.email)
16
16
 
17
- redirect_to profile_edit_path, flash: { status: "profile-updated" }
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: "profile/partials/delete_user_form", status: :unprocessable_entity if @delete_user_form.invalid?
23
+ return render partial: 'profile/partials/delete_user_form', status: :unprocessable_entity if @delete_user_form.invalid?
24
24
 
25
- user = Current.user
25
+ user = Current.auth.user
26
26
 
27
- logout
27
+ Current.auth.logout
28
28
 
29
29
  user.delete
30
30
 
31
- redirect_to "/"
31
+ reset_session
32
+
33
+ redirect_to '/'
32
34
  end
33
35
  end
@@ -1,5 +1,5 @@
1
1
  class WelcomeController < ApplicationController
2
- skip_authentication
2
+ skip_authenticate
3
3
 
4
4
  def index
5
5
  render layout: nil
@@ -1,8 +1,8 @@
1
- import "@hotwired/turbo-rails"
1
+ import '@hotwired/turbo-rails'
2
2
 
3
- import Alpine from "alpinejs"
3
+ import Alpine from 'alpinejs'
4
4
  window.Alpine = Alpine
5
5
 
6
- document.addEventListener("DOMContentLoaded", function(event) {
6
+ document.addEventListener('DOMContentLoaded', function (event) {
7
7
  window.Alpine.start()
8
8
  })
@@ -1,23 +1,18 @@
1
1
  <div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
2
- Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.
2
+ Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.
3
3
  </div>
4
-
5
4
  <!-- Session Status -->
6
5
  <%= render(AuthSessionStatusComponent.new({ class: "mb-4", status: flash[:status] })) %>
7
-
8
6
  <%= form_with model: @form, url: password_request_path do |form| %>
9
- <!-- Email Address -->
10
- <div>
11
- <%= render(InputLabelComponent.new({ for: "email", value: "Email" })) %>
12
-
13
- <%= render(TextInputComponent.new({ id: "email", class: "block mt-1 w-full", type: "email", name: "email", value: @form.email, required: true, autofocus: true, autocomplete: "username" })) %>
14
-
15
- <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:email] })) %>
16
- </div>
17
-
18
- <div class="flex items-center justify-end mt-4">
19
- <%= render(PrimaryButtonComponent.new) do %>
20
- Email Password Reset Link
21
- <% end %>
22
- </div>
7
+ <!-- Email Address -->
8
+ <div>
9
+ <%= render(InputLabelComponent.new({ for: "email", value: "Email" })) %>
10
+ <%= render(TextInputComponent.new({ id: "email", class: "block mt-1 w-full", type: "email", name: "email", value: @form.email, required: true, autofocus: true, autocomplete: "username" })) %>
11
+ <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:email] })) %>
12
+ </div>
13
+ <div class="flex items-center justify-end mt-4">
14
+ <%= render(PrimaryButtonComponent.new) do %>
15
+ Email Password Reset Link
16
+ <% end %>
17
+ </div>
23
18
  <% end %>
@@ -1,25 +1,18 @@
1
1
  <!-- Session Status -->
2
2
  <%= render(AuthSessionStatusComponent.new({ class: "mb-4", status: flash[:status] })) %>
3
-
4
3
  <%= form_with model: @form, url: login_path do |form| %>
5
4
  <!-- Email Address -->
6
5
  <div>
7
6
  <%= render(InputLabelComponent.new({ for: "email", value: "Email" })) %>
8
-
9
7
  <%= render(TextInputComponent.new({ id: "email", class: "block mt-1 w-full", type: "email", name: "email", value: @form.email, required: true, autofocus: true, autocomplete: "username" })) %>
10
-
11
8
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:email] })) %>
12
9
  </div>
13
-
14
10
  <!-- Password -->
15
11
  <div class="mt-4">
16
12
  <%= render(InputLabelComponent.new({ for: "password", value: "Password" })) %>
17
-
18
13
  <%= render(TextInputComponent.new({ id: "password", class: "block mt-1 w-full", type: "password", name: "password", required: true, autocomplete: "current-password" })) %>
19
-
20
14
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password] })) %>
21
15
  </div>
22
-
23
16
  <!-- Remember Me -->
24
17
  <div class="block mt-4">
25
18
  <label for="remember_me" class="inline-flex items-center">
@@ -27,12 +20,10 @@
27
20
  <span class="ms-2 text-sm text-gray-600 dark:text-gray-400">Remember me</span>
28
21
  </label>
29
22
  </div>
30
-
31
23
  <div class="flex items-center justify-end mt-4">
32
24
  <a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="<%= password_request_path %>">
33
25
  Forgot your password?
34
26
  </a>
35
-
36
27
  <%= render(PrimaryButtonComponent.new({ class: "ms-4" })) do %>
37
28
  Login
38
29
  <% end %>
@@ -2,44 +2,31 @@
2
2
  <!-- Name -->
3
3
  <div>
4
4
  <%= render(InputLabelComponent.new({ for: "name", value: "Name" })) %>
5
-
6
5
  <%= render(TextInputComponent.new({ id: "name", class: "block mt-1 w-full", type: "text", name: "name", value: @form.name, required: true, autofocus: true, autocomplete: "name" })) %>
7
-
8
6
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:name] })) %>
9
7
  </div>
10
-
11
8
  <!-- Email Address -->
12
9
  <div class="mt-4">
13
10
  <%= render(InputLabelComponent.new({ for: "email", value: "Email" })) %>
14
-
15
11
  <%= render(TextInputComponent.new({ id: "email", class: "block mt-1 w-full", type: "email", name: "email", value: @form.email, required: true, autocomplete: "username" })) %>
16
-
17
12
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:email] })) %>
18
13
  </div>
19
-
20
14
  <!-- Password -->
21
15
  <div class="mt-4">
22
16
  <%= render(InputLabelComponent.new({ for: "password", value: "Password" })) %>
23
-
24
17
  <%= render(TextInputComponent.new({ id: "password", class: "block mt-1 w-full", type: "password", name: "password", required: true, autocomplete: "new-password" })) %>
25
-
26
18
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password] })) %>
27
19
  </div>
28
-
29
20
  <!-- Confirm Password -->
30
21
  <div class="mt-4">
31
22
  <%= render(InputLabelComponent.new({ for: "password_confirmation", value: "Confirm Password" })) %>
32
-
33
23
  <%= render(TextInputComponent.new({ id: "password_confirmation", class: "block mt-1 w-full", type: "password", name: "password_confirmation", required: true, autocomplete: "new-password" })) %>
34
-
35
24
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password_confirmation] })) %>
36
25
  </div>
37
-
38
26
  <div class="flex items-center justify-end mt-4">
39
27
  <a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="<%= login_path %>">
40
28
  Already registered?
41
29
  </a>
42
-
43
30
  <%= render(PrimaryButtonComponent.new({ class: "ms-4" })) do %>
44
31
  Register
45
32
  <% end %>
@@ -1,25 +1,18 @@
1
1
  <%= form_with model: @form, url: password_store_path do |form| %>
2
2
  <!-- Password Reset Token -->
3
3
  <input type="hidden" name="token" value="<%= @form.token %>">
4
-
5
4
  <!-- Password -->
6
5
  <div>
7
6
  <%= render(InputLabelComponent.new({ for: "password", value: "Password" })) %>
8
-
9
7
  <%= render(TextInputComponent.new({ id: "password", class: "block mt-1 w-full", type: "password", name: "password", required: true, autofocus: true, autocomplete: "new-password" })) %>
10
-
11
8
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password] })) %>
12
9
  </div>
13
-
14
10
  <!-- Confirm Password -->
15
11
  <div class="mt-4">
16
12
  <%= render(InputLabelComponent.new({ for: "password_confirmation", value: "Confirm Password" })) %>
17
-
18
13
  <%= render(TextInputComponent.new({ id: "password_confirmation", class: "block mt-1 w-full", type: "password", name: "password_confirmation", required: true, autocomplete: "new-password" })) %>
19
-
20
14
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password_confirmation] })) %>
21
15
  </div>
22
-
23
16
  <div class="flex items-center justify-end mt-4">
24
17
  <%= render(PrimaryButtonComponent.new) do %>
25
18
  Reset Password
@@ -1,15 +1,14 @@
1
1
  <% content_for(:header) do %>
2
- <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
3
- Dashboard
4
- </h2>
2
+ <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
3
+ Dashboard
4
+ </h2>
5
5
  <% end %>
6
-
7
6
  <div class="py-12">
8
- <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
9
- <div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
10
- <div class="p-6 text-gray-900 dark:text-gray-100">
11
- You're logged in!
12
- </div>
13
- </div>
7
+ <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
8
+ <div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
9
+ <div class="p-6 text-gray-900 dark:text-gray-100">
10
+ You're logged in!
11
+ </div>
14
12
  </div>
13
+ </div>
15
14
  </div>
@@ -1,92 +1,82 @@
1
1
  <nav x-data="{ open: false }" class="bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700">
2
- <!-- Primary Navigation Menu -->
3
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
4
- <div class="flex justify-between h-16">
5
- <div class="flex">
6
- <!-- Logo -->
7
- <div class="shrink-0 flex items-center">
8
- <a href="<%= dashboard_path %>">
9
- <%= render(ApplicationLogoComponent.new({ class: "block h-9 w-auto fill-current text-gray-800 dark:text-gray-200" })) %>
10
- </a>
11
- </div>
12
-
13
- <!-- Navigation Links -->
14
- <div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
15
- <%= render(NavLinkComponent.new({ href: dashboard_path })) do %>
16
- Dashboard
17
- <% end %>
18
- </div>
19
- </div>
20
-
21
- <!-- Settings Dropdown -->
22
- <div class="hidden sm:flex sm:items-center sm:ms-6">
23
- <%= render DropdownComponent.new do |component| %>
24
- <% component.with_trigger(classes: "") do %>
25
- <button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none transition ease-in-out duration-150">
26
- <div><%= Current.user.name %></div>
27
-
28
- <div class="ms-1">
29
- <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
30
- <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
31
- </svg>
32
- </div>
33
- </button>
34
- <% end %>
35
-
36
- <%= render(DropdownLinkComponent.new({ href: profile_edit_path })) do %>
37
- Profile
38
- <% end %>
39
-
40
- <!-- Authentication -->
41
- <form method="POST" action="<%= logout_path %>">
42
- <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
43
- <%= render(DropdownLinkComponent.new({ href: logout_path, onclick: "event.preventDefault();this.closest('form').submit();" })) do %>
44
- Log Out
45
- <% end %>
46
- </form>
47
- <% end %>
48
- </div>
49
-
50
- <!-- Hamburger -->
51
- <div class="-me-2 flex items-center sm:hidden">
52
- <button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-900 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-500 dark:focus:text-gray-400 transition duration-150 ease-in-out">
53
- <svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
54
- <path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
55
- <path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
56
- </svg>
57
- </button>
58
- </div>
2
+ <!-- Primary Navigation Menu -->
3
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
4
+ <div class="flex justify-between h-16">
5
+ <div class="flex">
6
+ <!-- Logo -->
7
+ <div class="shrink-0 flex items-center">
8
+ <a href="/">
9
+ <%= render(ApplicationLogoComponent.new({ class: "block h-9 w-auto fill-current text-gray-800 dark:text-gray-200" })) %>
10
+ </a>
59
11
  </div>
60
- </div>
61
-
62
- <!-- Responsive Navigation Menu -->
63
- <div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
64
- <div class="pt-2 pb-3 space-y-1">
65
- <%= render(ResponsiveNavLinkComponent.new({ href: dashboard_path })) do %>
66
- Dashboard
67
- <% end %>
68
- </div>
69
-
70
- <!-- Responsive Settings Options -->
71
- <div class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-600">
72
- <div class="px-4">
73
- <div class="font-medium text-base text-gray-800 dark:text-gray-200"><%= Current.user.name %></div>
74
- <div class="font-medium text-sm text-gray-500"><%= Current.user.email %></div>
75
- </div>
76
-
77
- <div class="mt-3 space-y-1">
78
- <%= render(ResponsiveNavLinkComponent.new({ href: profile_edit_path })) do %>
79
- Profile
80
- <% end %>
81
-
82
- <!-- Authentication -->
83
- <form method="POST" action="<%= logout_path %>">
84
- <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
85
- <%= render(ResponsiveNavLinkComponent.new({ href: logout_path, onclick: "event.preventDefault();this.closest('form').submit();" })) do %>
86
- Log Out
87
- <% end %>
88
- </form>
89
- </div>
12
+ <!-- Navigation Links -->
13
+ <div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
14
+ <%= render(NavLinkComponent.new({ href: dashboard_path, active: current_page?(dashboard_path) })) do %>
15
+ Dashboard
16
+ <% end %>
90
17
  </div>
18
+ </div>
19
+ <!-- Settings Dropdown -->
20
+ <div class="hidden sm:flex sm:items-center sm:ms-6">
21
+ <%= render DropdownComponent.new do |component| %>
22
+ <% component.with_trigger(classes: "") do %>
23
+ <button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none transition ease-in-out duration-150">
24
+ <div><%= Current.auth.user.name %></div>
25
+ <div class="ms-1">
26
+ <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
27
+ <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
28
+ </svg>
29
+ </div>
30
+ </button>
31
+ <% end %>
32
+ <%= render(DropdownLinkComponent.new({ href: profile_edit_path })) do %>
33
+ Profile
34
+ <% end %>
35
+ <!-- Authentication -->
36
+ <form method="POST" action="<%= logout_path %>">
37
+ <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
38
+ <%= render(DropdownLinkComponent.new({ href: logout_path, onclick: "event.preventDefault();this.closest('form').submit()" })) do %>
39
+ Log Out
40
+ <% end %>
41
+ </form>
42
+ <% end %>
43
+ </div>
44
+ <!-- Hamburger -->
45
+ <div class="-me-2 flex items-center sm:hidden">
46
+ <button x-on:click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-900 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-500 dark:focus:text-gray-400 transition duration-150 ease-in-out">
47
+ <svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
48
+ <path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
49
+ <path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
50
+ </svg>
51
+ </button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ <!-- Responsive Navigation Menu -->
56
+ <div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
57
+ <div class="pt-2 pb-3 space-y-1">
58
+ <%= render(ResponsiveNavLinkComponent.new({ href: dashboard_path, active: current_page?(dashboard_path) })) do %>
59
+ Dashboard
60
+ <% end %>
61
+ </div>
62
+ <!-- Responsive Settings Options -->
63
+ <div class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-600">
64
+ <div class="px-4">
65
+ <div class="font-medium text-base text-gray-800 dark:text-gray-200"><%= Current.auth.user.name %></div>
66
+ <div class="font-medium text-sm text-gray-500"><%= Current.auth.user.email %></div>
67
+ </div>
68
+ <div class="mt-3 space-y-1">
69
+ <%= render(ResponsiveNavLinkComponent.new({ href: profile_edit_path })) do %>
70
+ Profile
71
+ <% end %>
72
+ <!-- Authentication -->
73
+ <form method="POST" action="<%= logout_path %>">
74
+ <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
75
+ <%= render(ResponsiveNavLinkComponent.new({ href: logout_path, onclick: "event.preventDefault();this.closest('form').submit()" })) do %>
76
+ Log Out
77
+ <% end %>
78
+ </form>
79
+ </div>
91
80
  </div>
81
+ </div>
92
82
  </nav>