kaze 0.4.0 → 0.6.0

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