kaze 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kaze/commands/install_command.rb +18 -4
  3. data/lib/kaze/commands/installs_hotwire_stack.rb +5 -2
  4. data/lib/kaze/commands/installs_inertia_stacks.rb +13 -3
  5. data/lib/kaze/version.rb +1 -1
  6. data/stubs/default/app/forms/auth/login_form.rb +2 -8
  7. data/stubs/default/app/forms/update_profile_information_form.rb +1 -1
  8. data/stubs/default/app/models/auth.rb +57 -0
  9. data/stubs/default/app/models/current.rb +1 -1
  10. data/stubs/default/app/validators/current_password_validator.rb +1 -1
  11. data/stubs/default/app/views/layouts/mailer.html.erb +367 -372
  12. data/stubs/default/app/views/layouts/mailer.text.erb +1 -4
  13. data/stubs/default/app/views/user_mailer/reset_password.html.erb +21 -26
  14. data/stubs/default/test/factories/users.rb +7 -0
  15. data/stubs/default/test/integration/auth/authentication_test.rb +43 -0
  16. data/stubs/default/test/integration/auth/password_reset_test.rb +41 -0
  17. data/stubs/default/test/integration/auth/registration_test.rb +21 -0
  18. data/stubs/default/test/integration/password_update_test.rb +28 -0
  19. data/stubs/default/test/integration/profile_test.rb +51 -0
  20. data/stubs/default/test/test_helper.rb +38 -0
  21. data/stubs/hotwire/app/components/dropdown_component.html.erb +17 -18
  22. data/stubs/hotwire/app/components/modal_component.html.erb +55 -59
  23. data/stubs/hotwire/app/controllers/application_controller.rb +1 -0
  24. data/stubs/hotwire/app/controllers/auth/authenticated_session_controller.rb +10 -7
  25. data/stubs/hotwire/app/controllers/auth/new_password_controller.rb +3 -1
  26. data/stubs/hotwire/app/controllers/auth/password_reset_link_controller.rb +3 -1
  27. data/stubs/hotwire/app/controllers/auth/registered_user_controller.rb +4 -2
  28. data/stubs/hotwire/app/controllers/concerns/authenticate.rb +5 -20
  29. data/stubs/hotwire/app/controllers/concerns/redirect_if_authenticated.rb +19 -0
  30. data/stubs/hotwire/app/controllers/concerns/set_current_auth.rb +9 -0
  31. data/stubs/hotwire/app/controllers/password_controller.rb +1 -1
  32. data/stubs/hotwire/app/controllers/profile_controller.rb +6 -4
  33. data/stubs/hotwire/app/controllers/welcome_controller.rb +1 -1
  34. data/stubs/hotwire/app/javascript/application.js +3 -3
  35. data/stubs/hotwire/app/views/auth/forgot_password.html.erb +12 -17
  36. data/stubs/hotwire/app/views/auth/login.html.erb +0 -9
  37. data/stubs/hotwire/app/views/auth/register.html.erb +0 -13
  38. data/stubs/hotwire/app/views/auth/reset_password.html.erb +0 -7
  39. data/stubs/hotwire/app/views/dashboard/index.html.erb +9 -10
  40. data/stubs/hotwire/app/views/layouts/_navigation.html.erb +77 -87
  41. data/stubs/hotwire/app/views/layouts/application.html.erb +0 -9
  42. data/stubs/hotwire/app/views/layouts/guest.html.erb +0 -6
  43. data/stubs/hotwire/app/views/profile/edit.html.erb +19 -22
  44. data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +32 -42
  45. data/stubs/hotwire/app/views/profile/partials/_update_password_form.html.erb +42 -55
  46. data/stubs/hotwire/app/views/profile/partials/_update_profile_information_form.html.erb +36 -46
  47. data/stubs/hotwire/app/views/welcome/index.html.erb +34 -46
  48. data/stubs/hotwire/config/tailwind.config.js +2 -2
  49. data/stubs/inertia-common/app/controllers/application_controller.rb +1 -0
  50. data/stubs/inertia-common/app/controllers/auth/authenticated_session_controller.rb +10 -7
  51. data/stubs/inertia-common/app/controllers/auth/new_password_controller.rb +3 -1
  52. data/stubs/inertia-common/app/controllers/auth/password_reset_link_controller.rb +3 -1
  53. data/stubs/inertia-common/app/controllers/auth/registered_user_controller.rb +4 -2
  54. data/stubs/inertia-common/app/controllers/concerns/authenticate.rb +5 -20
  55. data/stubs/inertia-common/app/controllers/concerns/handle_inertia_requests.rb +1 -1
  56. data/stubs/inertia-common/app/controllers/concerns/redirect_if_authenticated.rb +19 -0
  57. data/stubs/inertia-common/app/controllers/concerns/set_current_auth.rb +9 -0
  58. data/stubs/inertia-common/app/controllers/password_controller.rb +1 -1
  59. data/stubs/inertia-common/app/controllers/profile_controller.rb +5 -3
  60. data/stubs/inertia-common/app/controllers/welcome_controller.rb +1 -1
  61. data/stubs/inertia-common/test/integration/password_update_test.rb +28 -0
  62. data/stubs/inertia-common/test/integration/profile_test.rb +51 -0
  63. data/stubs/inertia-react-ts/app/javascript/Components/ApplicationLogo.tsx +13 -9
  64. data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +12 -12
  65. data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +20 -15
  66. data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +115 -88
  67. data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +14 -7
  68. data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +15 -7
  69. data/stubs/inertia-react-ts/app/javascript/Components/Modal.tsx +60 -60
  70. data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +21 -16
  71. data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +20 -15
  72. data/stubs/inertia-react-ts/app/javascript/Components/ResponsiveNavLink.tsx +19 -14
  73. data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +22 -16
  74. data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +32 -24
  75. data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +157 -117
  76. data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +15 -15
  77. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +52 -49
  78. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +90 -82
  79. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +118 -115
  80. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +63 -60
  81. data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +23 -17
  82. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +31 -27
  83. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +109 -99
  84. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx +121 -113
  85. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx +76 -69
  86. data/stubs/inertia-react-ts/app/javascript/Pages/Welcome.tsx +87 -63
  87. data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +32 -25
  88. data/stubs/inertia-react-ts/app/views/layouts/application.html.erb +0 -4
  89. data/stubs/inertia-react-ts/config/tailwind.config.js +2 -2
  90. data/stubs/inertia-react-ts/vite.config.ts +2 -5
  91. data/stubs/inertia-vue-ts/app/javascript/Components/ApplicationLogo.vue +10 -6
  92. data/stubs/inertia-vue-ts/app/javascript/Components/Checkbox.vue +18 -18
  93. data/stubs/inertia-vue-ts/app/javascript/Components/DangerButton.vue +5 -5
  94. data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +60 -57
  95. data/stubs/inertia-vue-ts/app/javascript/Components/DropdownLink.vue +9 -9
  96. data/stubs/inertia-vue-ts/app/javascript/Components/InputError.vue +7 -7
  97. data/stubs/inertia-vue-ts/app/javascript/Components/InputLabel.vue +6 -6
  98. data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +84 -74
  99. data/stubs/inertia-vue-ts/app/javascript/Components/NavLink.vue +12 -12
  100. data/stubs/inertia-vue-ts/app/javascript/Components/PrimaryButton.vue +5 -5
  101. data/stubs/inertia-vue-ts/app/javascript/Components/ResponsiveNavLink.vue +12 -12
  102. data/stubs/inertia-vue-ts/app/javascript/Components/SecondaryButton.vue +13 -13
  103. data/stubs/inertia-vue-ts/app/javascript/Components/TextInput.vue +13 -13
  104. data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +168 -136
  105. data/stubs/inertia-vue-ts/app/javascript/Layouts/GuestLayout.vue +15 -13
  106. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +56 -49
  107. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +78 -72
  108. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +101 -97
  109. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +71 -68
  110. data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +22 -14
  111. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +34 -30
  112. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +87 -83
  113. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue +105 -98
  114. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue +69 -59
  115. data/stubs/inertia-vue-ts/app/javascript/Pages/Welcome.vue +74 -47
  116. data/stubs/inertia-vue-ts/app/views/layouts/application.html.erb +0 -4
  117. data/stubs/inertia-vue-ts/config/tailwind.config.js +2 -2
  118. data/stubs/inertia-vue-ts/vite.config.ts +2 -5
  119. metadata +18 -6
  120. data/stubs/hotwire/bin/vite +0 -27
  121. data/stubs/inertia-common/Procfile.dev +0 -3
  122. /data/stubs/{hotwire → default}/Procfile.dev +0 -0
  123. /data/stubs/hotwire/app/javascript/{alpinejs.js → alpinejs.stub} +0 -0
@@ -1,6 +1,6 @@
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
 
@@ -12,7 +12,7 @@ class ProfileController < ApplicationController
12
12
 
13
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
17
  redirect_to profile_edit_path, flash: { status: 'profile-updated' }
18
18
  end
@@ -22,12 +22,14 @@ class ProfileController < ApplicationController
22
22
 
23
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
+ reset_session
32
+
31
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>
@@ -3,27 +3,19 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1">
6
-
7
6
  <title><%= content_for(:title) || "Rails" %></title>
8
-
9
7
  <%= csrf_meta_tags %>
10
8
  <%= csp_meta_tag %>
11
-
12
9
  <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
13
-
14
10
  <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
15
11
  <%= javascript_importmap_tags %>
16
-
17
12
  <%= hotwire_livereload_tags if Rails.env.development? %>
18
13
  <%= turbo_refreshes_with method: :morph, scroll: :preserve %>
19
-
20
14
  <%= yield :head %>
21
15
  </head>
22
-
23
16
  <body class="font-sans antialiased">
24
17
  <div class="min-h-screen bg-gray-100">
25
18
  <%= render "layouts/navigation" %>
26
-
27
19
  <!-- Page Heading -->
28
20
  <% if content_for?(:header) %>
29
21
  <header class="bg-white dark:bg-gray-800 shadow">
@@ -32,7 +24,6 @@
32
24
  </div>
33
25
  </header>
34
26
  <% end %>
35
-
36
27
  <!-- Page Content -->
37
28
  <main>
38
29
  <%= yield %>
@@ -3,17 +3,12 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1">
6
-
7
6
  <title><%= content_for(:title) || "Rails" %></title>
8
-
9
7
  <%= csrf_meta_tags %>
10
8
  <%= csp_meta_tag %>
11
-
12
9
  <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
13
-
14
10
  <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
15
11
  <%= javascript_importmap_tags %>
16
-
17
12
  <%= hotwire_livereload_tags if Rails.env.development? %>
18
13
  <%= turbo_refreshes_with method: :morph, scroll: :preserve %>
19
14
  </head>
@@ -24,7 +19,6 @@
24
19
  <%= render(ApplicationLogoComponent.new({ class: "w-20 h-20 fill-current text-gray-500" })) %>
25
20
  </a>
26
21
  </div>
27
-
28
22
  <div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white dark:bg-gray-800 shadow-md overflow-hidden sm:rounded-lg">
29
23
  <%= yield %>
30
24
  </div>
@@ -1,27 +1,24 @@
1
1
  <% content_for(:header) do %>
2
- <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
3
- Profile
4
- </h2>
2
+ <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
3
+ Profile
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 space-y-6">
9
- <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
10
- <div class="max-w-xl">
11
- <%= render "profile/partials/update_profile_information_form" %>
12
- </div>
13
- </div>
14
-
15
- <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
16
- <div class="max-w-xl">
17
- <%= render "profile/partials/update_password_form" %>
18
- </div>
19
- </div>
20
-
21
- <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
22
- <div class="max-w-xl">
23
- <%= render "profile/partials/delete_user_form" %>
24
- </div>
25
- </div>
7
+ <div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
8
+ <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
9
+ <div class="max-w-xl">
10
+ <%= render "profile/partials/update_profile_information_form" %>
11
+ </div>
26
12
  </div>
13
+ <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
14
+ <div class="max-w-xl">
15
+ <%= render "profile/partials/update_password_form" %>
16
+ </div>
17
+ </div>
18
+ <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
19
+ <div class="max-w-xl">
20
+ <%= render "profile/partials/delete_user_form" %>
21
+ </div>
22
+ </div>
23
+ </div>
27
24
  </div>
@@ -1,48 +1,38 @@
1
1
  <section class="space-y-6">
2
- <header>
2
+ <header>
3
+ <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
4
+ Delete Account
5
+ </h2>
6
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
7
+ Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.
8
+ </p>
9
+ </header>
10
+ <%= render(DangerButtonComponent.new({"x-data": "", "x-on:click.prevent": "$dispatch('open-modal', 'confirm-user-deletion')"})) do %>
11
+ Delete Account
12
+ <% end %>
13
+ <%= render(ModalComponent.new({ :name => "confirm-user-deletion", :show => @delete_user_form.error_messages.has_key?(:password), :focusable => true })) do %>
14
+ <turbo-frame id="delete_user_form">
15
+ <%= form_with model: @delete_user_form, url: profile_destroy_path, method: "delete", class: "p-6" do %>
3
16
  <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
4
- Delete Account
17
+ Are you sure you want to delete your account?
5
18
  </h2>
6
-
7
19
  <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
8
- Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.
20
+ Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.
9
21
  </p>
10
- </header>
11
-
12
- <%= render(DangerButtonComponent.new({"x-data": "", "x-on:click.prevent": "$dispatch('open-modal', 'confirm-user-deletion')"})) do %>
13
- Delete Account
14
- <% end %>
15
-
16
- <%= render(ModalComponent.new({ :name => "confirm-user-deletion", :show => @delete_user_form.error_messages.has_key?(:password), :focusable => true })) do %>
17
- <turbo-frame id="delete_user_form">
18
- <%= form_with model: @delete_user_form, url: profile_destroy_path, method: "delete", class: "p-6" do %>
19
- <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
20
- Are you sure you want to delete your account?
21
- </h2>
22
-
23
- <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
24
- Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.
25
- </p>
26
-
27
- <div class="mt-6">
28
- <%= render(InputLabelComponent.new({ for: "password", value: "Password", class: "sr-only" })) %>
29
-
30
- <%= render(TextInputComponent.new({ id: "password", class: "mt-1 block w-3/4", type: "password", name: "password", placeholder: "Password" })) %>
31
-
32
- <%= render(InputErrorComponent.new({ class: "mt-2", message: @delete_user_form.error_messages[:password] })) %>
33
- </div>
34
-
35
- <div class="mt-6 flex justify-end">
36
- <%= render(SecondaryButtonComponent.new({ "x-on:click": "$dispatch('close')" })) do %>
37
- Cancel
38
- <% end %>
39
-
40
- <%= render(DangerButtonComponent.new({ class: "ms-3" })) do %>
41
- Delete Account
42
- <% end %>
43
- </div>
44
- <% end %>
45
- </turbo-frame>
46
- <% end %>
22
+ <div class="mt-6">
23
+ <%= render(InputLabelComponent.new({ for: "password", value: "Password", class: "sr-only" })) %>
24
+ <%= render(TextInputComponent.new({ id: "password", class: "mt-1 block w-3/4", type: "password", name: "password", placeholder: "Password" })) %>
25
+ <%= render(InputErrorComponent.new({ class: "mt-2", message: @delete_user_form.error_messages[:password] })) %>
26
+ </div>
27
+ <div class="mt-6 flex justify-end">
28
+ <%= render(SecondaryButtonComponent.new({ "x-on:click": "$dispatch('close')" })) do %>
29
+ Cancel
30
+ <% end %>
31
+ <%= render(DangerButtonComponent.new({ class: "ms-3" })) do %>
32
+ Delete Account
33
+ <% end %>
34
+ </div>
35
+ <% end %>
36
+ </turbo-frame>
37
+ <% end %>
47
38
  </section>
48
-