kaze 2.0.1 → 2.1.1

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -1
  3. data/README.md +42 -2
  4. data/lib/kaze/commands/app/base_stack.rb +25 -0
  5. data/lib/kaze/commands/app/hotwire_stack.rb +18 -0
  6. data/lib/kaze/commands/app/inertia_react_stack.rb +23 -0
  7. data/lib/kaze/commands/app/inertia_vue_stack.rb +24 -0
  8. data/lib/kaze/commands/app.rb +49 -4
  9. data/lib/kaze/version.rb +1 -1
  10. data/stubs/hotwire/app/views/auth/forgot_password.html.erb +1 -1
  11. data/stubs/hotwire/app/views/auth/login.html.erb +1 -1
  12. data/stubs/hotwire/app/views/auth/register.html.erb +2 -2
  13. data/stubs/hotwire/app/views/auth/reset_password.html.erb +3 -3
  14. data/stubs/hotwire/app/views/auth/verify_email.html.erb +2 -2
  15. data/stubs/hotwire/app/views/layouts/_sidebar_user.html.erb +1 -1
  16. data/stubs/hotwire/app/views/settings/password/_update_password_form.html.erb +6 -6
  17. data/stubs/hotwire/app/views/settings/profile/_confirm_user_deletion_modal.html.erb +1 -1
  18. data/stubs/hotwire/app/views/settings/profile/_delete_user_form.html.erb +1 -1
  19. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +2 -2
  20. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +1 -1
  21. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +3 -3
  22. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/VerifyEmail.tsx +3 -3
  23. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Partials/DeleteUserForm.tsx +2 -2
  24. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Partials/UpdatePasswordForm.tsx +3 -3
  25. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +2 -2
  26. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +1 -1
  27. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +3 -3
  28. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/VerifyEmail.vue +3 -3
  29. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Partials/DeleteUserForm.vue +2 -2
  30. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Partials/UpdatePasswordForm.vue +3 -3
  31. metadata +15 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e59ed35aebe912f3109e4cf1937daa83a61d11235e2052d4d148c4d67f29fd52
4
- data.tar.gz: 0c5844feaa1dd744199e50af4aecbb0f53ca8f5ea2a6060b6362b124f16a8762
3
+ metadata.gz: 55a910134ce65d8e8401e8093507fc565efaf81d54df89873d5541cb51214b1b
4
+ data.tar.gz: b6d8afe1350896e1fb047d753d7271204e1ffd8ba1127504311799af0704deeb
5
5
  SHA512:
6
- metadata.gz: a02c56cd8f4e53405776b9d1240b54b5fe6b6a71f01339a90fe83a04f0864ebef3f68a8d5a6f41e2a80ae9b3d4d70ce376c4a165ec4c38d9354bfe874b969d66
7
- data.tar.gz: 512b952e164d688a07204f3d3137b39215b5753bdeab6a01543562d3a9156960d0e383ffdd0798270aa75440187fcaa939d756bab7c6316637ac8d00d71cfa52
6
+ metadata.gz: 7692a5a56a442c9dc100ee7236e1c611b6ce3d53a03b012386f308b0179780864c395ddcc56fb15cb92c013bc5be11aeef7bd4a3e1eabb2209731cb635da73fc
7
+ data.tar.gz: 46e3659514c1f9820f01aa89a71be012a41efbdccc79861f035b75565ade82557e6a0b3b0f1a4d657cdccd94d0ff181e333fe9ff0e0f1918b2a65344a135c54d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.1.1] - 2026-10-25
10
+
11
+ ### Fixed
12
+
13
+ - User-visible text now reads the same across the three stacks and within a page. Hotwire's login button said "Login" where React and Vue said "Log in", which is what prompted this — but the sweep found the real problem was that the 2.0.0 settings area introduced sentence case ("Profile information", "Delete account") while the auth pages kept the title case inherited from Breeze ("Reset Password", "Confirm Password"), so the two conventions met inside the same screen. The delete-account page had a "Delete account" heading directly above a "Delete Account" button.
14
+
15
+ Everything settles on sentence case, matching the settings area and Laravel's current kits: "Log in", "Log out", "Reset password", "Confirm password", "Current password", "New password", "Delete account", "Email password reset link", "Resend verification email", and the "Forgot password" and "Email verification" page titles. Mailer copy is left in title case — a different surface, and Laravel's reset email keeps it too.
16
+
17
+ ### Documentation
18
+
19
+ - Screenshots and badges in the README. A starter kit whose selling point is what it looks like had no picture of itself anywhere — someone evaluating Kaze had to install it to find out. Three captures of the real scaffolded application cover the sidebar shell, the settings area and both themes, at 48 KB in total and outside the gem's packaged files.
20
+
21
+ - A README section on the frontend. The 2.0.0 redesign is the largest change this project has had and the README described none of it — what shadcn/ui means here, that the primitives are yours to edit, how to add more with `npx shadcn@latest add`, the capitalised `@/Components` alias that will bite anyone hand-writing an import, the token and appearance systems, and why the Hotwire stack hand-rolls its own equivalents.
22
+
23
+ ### Internal
24
+
25
+ - A test suite for the gem itself, run by `rake test` and by a new `Gem Tests` job in CI. Until now the only automated coverage was the scaffolded applications' own tests, which exercise the stubs but never the code that copies them.
26
+
27
+ The bulk of it covers `kaze upgrade`, since that is the part that deletes files from a real application: that a directory is pruned only once empty, that one still holding someone else's work survives along with the file in it, that nothing above `app/` is ever touched, and that a path missing from the application is skipped rather than raised on. The rest pins the removal manifests — no listed path may still be shipped by the stubs, which would have `upgrade` delete a file the install puts straight back — and checks that `lib/kaze/version.rb` matches the newest changelog heading, so a release cannot ship a version the changelog does not describe.
28
+
29
+ The tests are excluded from the built gem.
30
+
31
+ ## [2.1.0] - 2026-10-22
32
+
33
+ ### Added
34
+
35
+ - A `kaze upgrade [STACK]` command. Kaze copies files into an application and does not own them afterwards, so `kaze install` cannot tell a leftover from an older version apart from something you wrote, and has always left both alone. `upgrade` resolves that by asking instead of guessing: it lists the files an earlier Kaze installed that this version no longer ships, waits for you to agree, removes them, and then runs the normal install.
36
+
37
+ Only paths Kaze itself shipped are ever offered — the list per stack is fixed in the source, so nothing you added alongside them can be caught by it, and a directory is removed only once it is empty. `--dry-run` prints the list and stops; `--force` skips the prompt for scripts. Declining exits non-zero and changes nothing.
38
+
39
+ This replaces the manual file list in the 2.0.0 upgrade notes below. On the React stack it is the difference between an upgraded application building and not: `tsc` typechecks every file under `app/javascript`, so the old `Pages/Profile/Edit.tsx` fails the build until it is gone.
40
+
9
41
  ## [2.0.1] - 2026-10-22
10
42
 
11
43
  ### Fixed
@@ -185,7 +217,9 @@ Together these take a freshly scaffolded Inertia application from seven npm advi
185
217
 
186
218
  Releases before 1.0.0 are not catalogued here. See the [tags](https://github.com/cuonggt/kaze/tags) for their history.
187
219
 
188
- [Unreleased]: https://github.com/cuonggt/kaze/compare/v2.0.1...HEAD
220
+ [Unreleased]: https://github.com/cuonggt/kaze/compare/v2.1.1...HEAD
221
+ [2.1.1]: https://github.com/cuonggt/kaze/compare/v2.1.0...v2.1.1
222
+ [2.1.0]: https://github.com/cuonggt/kaze/compare/v2.0.1...v2.1.0
189
223
  [2.0.1]: https://github.com/cuonggt/kaze/compare/v2.0.0...v2.0.1
190
224
  [2.0.0]: https://github.com/cuonggt/kaze/compare/v1.4.0...v2.0.0
191
225
  [1.4.0]: https://github.com/cuonggt/kaze/compare/v1.3.1...v1.4.0
data/README.md CHANGED
@@ -2,12 +2,24 @@
2
2
 
3
3
  # Kaze
4
4
 
5
+ [![Gem Version](https://img.shields.io/gem/v/kaze)](https://rubygems.org/gems/kaze)
6
+ [![Tests](https://github.com/cuonggt/kaze/actions/workflows/tests.yml/badge.svg)](https://github.com/cuonggt/kaze/actions/workflows/tests.yml)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE.md)
8
+
5
9
  Heavily inspired by [Laravel Breeze](https://github.com/laravel/breeze), this gem offers authentication and application starter kits to give you a head start building your new [Rails](https://rubyonrails.org) application. These kits automatically scaffold your application with the routes, controllers, and views you need to register and authenticate your application's users.
6
10
 
7
- [Kaze](https://github.com/cuonggt/kaze) is a opinionated minimal, simple implementation of all authentication features that a modern web application should have, including login, registration, password reset, email verification. In addition, Kaze includes a settings area where the user may update their name and email address, change their password, choose an appearance, and delete their account.
11
+ [Kaze](https://github.com/cuonggt/kaze) is an opinionated, minimal, simple implementation of all authentication features that a modern web application should have, including login, registration, password reset, and email verification. In addition, Kaze includes a settings area where the user may update their name and email address, change their password, choose an appearance, and delete their account.
8
12
 
9
13
  Kaze provides scaffolding options based on [Hotwire](https://hotwired.dev) or [Inertia](https://inertiajs.com), with the choice of using Vue or React for the Inertia-based scaffolding.
10
14
 
15
+ ![Profile settings](/art/screenshots/settings-light.jpg)
16
+
17
+ | | |
18
+ |---|---|
19
+ | ![The same page in dark mode](/art/screenshots/settings-dark.jpg) | ![Logging in](/art/screenshots/login-light.jpg) |
20
+
21
+ The three stacks are built to the same design, so these are from the React one.
22
+
11
23
  ## Installation
12
24
 
13
25
  Before creating your first project powered by Kaze, make sure that your local machine has Ruby installed. Ruby can be installed in minutes via [mise](https://mise.jdx.dev).
@@ -36,7 +48,7 @@ Once the project has been created, you may scaffold your application using one o
36
48
 
37
49
  ## Kaze and Hotwire
38
50
 
39
- The default Kaze "stack" is the Hotwire stack. Hotwire is a powerful way to building dynamic, reactive, front-end UIs primarily using Ruby and ERB templates without using much JavaScript by sending HTML instead of JSON over the wire.
51
+ The default Kaze "stack" is the Hotwire stack. Hotwire is a powerful way to build dynamic, reactive, front-end UIs primarily using Ruby and ERB templates without using much JavaScript by sending HTML instead of JSON over the wire.
40
52
 
41
53
  The Hotwire stack may be installed by invoking the `kaze install` command with no other additional arguments inside your app directory. This command publishes the authentication, views, routes, controllers, and other resources to your application.
42
54
 
@@ -75,3 +87,31 @@ bin/dev
75
87
  ```
76
88
 
77
89
  Next, you may navigate to your application's `/login` or `/register` URLs in your web browser. All of Kaze's routes are defined within the `config/routes.rb` file.
90
+
91
+ ## The frontend
92
+
93
+ Both Inertia stacks are built on [shadcn/ui](https://ui.shadcn.com) — thirteen primitives apiece (button, input, label, checkbox, dialog, dropdown menu, separator, skeleton, sheet, tooltip, avatar, breadcrumb and sidebar), on Radix for React and [reka-ui](https://reka-ui.com) for Vue. shadcn copies source into a project rather than shipping a package, which is how Kaze already works, so these land in `app/javascript/Components/ui` and are yours to change.
94
+
95
+ A `components.json` comes with them, so you can add more:
96
+
97
+ ```
98
+ npx shadcn@latest add card
99
+ ```
100
+
101
+ One thing to know if you reach for that: Kaze uses a capitalised `@/Components`, which `components.json` already records. The CLI will follow it, but an import you write by hand as `@/components/ui/card` will resolve on macOS and fail on Linux.
102
+
103
+ Colour runs through design tokens — `bg-background`, `text-muted-foreground`, `border-sidebar-border` and so on, defined once per stylesheet as oklch variables — rather than per-element `dark:` pairs. Appearance is a user preference of light, dark or system, stored in `localStorage` and applied before first paint so the page never flashes the wrong theme; system follows the device and tracks it live. The application layout is a sidebar that collapses to icons and becomes a drawer on small screens, remembering its state in a cookie the server reads back.
104
+
105
+ There is no shadcn for Hotwire. That stack gets the same look from ViewComponents written against the same tokens, with the handful of [lucide](https://lucide.dev) icons the layouts need inlined into an `IconComponent`, since it carries no npm dependencies at all.
106
+
107
+ ## Upgrading
108
+
109
+ Kaze copies files into your application and does not own them afterwards, so re-running `kaze install` cannot know whether a file it no longer ships was left over from an older version or written by you. `kaze upgrade` resolves that by asking:
110
+
111
+ ```
112
+ kaze upgrade react
113
+ ```
114
+
115
+ It lists the files an earlier Kaze installed that this version no longer ships, waits for you to agree, removes them, and then runs the normal install. Only files Kaze itself shipped are ever listed — anything you added alongside them is untouched, and a directory is removed only once it is empty. Pass `--dry-run` to see the list and stop, or `--force` to skip the prompt in a script.
116
+
117
+ Upgrading from 1.x to 2.x matters on the React stack in particular: `tsc` typechecks every file under `app/javascript`, so the old `Pages/Profile/Edit.tsx` fails the build until it is gone.
@@ -7,8 +7,33 @@ class Kaze::Commands::App::BaseStack
7
7
  raise NotImplementedError
8
8
  end
9
9
 
10
+ # Paths from this stack's REMOVED_PATHS that the application still has. Only
11
+ # ever a subset of that list: `kaze upgrade` never touches a path Kaze did not
12
+ # put there itself.
13
+ def removable_paths
14
+ self.class::REMOVED_PATHS.select { |path| File.exist?("#{Dir.pwd}/#{path}") }
15
+ end
16
+
17
+ def remove_paths(paths)
18
+ paths.each { |path| FileUtils.rm_f("#{Dir.pwd}/#{path}") }
19
+
20
+ prune_empty_directories(paths)
21
+ end
22
+
10
23
  private
11
24
 
25
+ # Deleting the last file in a directory leaves the directory behind. Walk back
26
+ # up from each one removing those that are now empty, and stop at the first
27
+ # that is not -- a directory with anything left in it is the application's.
28
+ def prune_empty_directories(paths)
29
+ paths.map { |path| File.dirname("#{Dir.pwd}/#{path}") }.uniq.sort_by(&:length).reverse.each do |dir|
30
+ while dir.start_with?("#{Dir.pwd}/app/") && Dir.exist?(dir) && Dir.empty?(dir)
31
+ Dir.rmdir(dir)
32
+ dir = File.dirname(dir)
33
+ end
34
+ end
35
+ end
36
+
12
37
  def bundle_command
13
38
  @bundle_command ||= File.exist?("#{Dir.pwd}/bin/bundle") ? "#{Dir.pwd}/bin/bundle" : 'bundle'
14
39
  end
@@ -1,4 +1,22 @@
1
1
  class Kaze::Commands::App::HotwireStack < Kaze::Commands::App::BaseStack
2
+ # Paths that earlier versions of Kaze installed here and this version no longer
3
+ # ships. `kaze upgrade` offers to delete whichever of them an application still
4
+ # has; anything removed in a future version belongs on this list too.
5
+ REMOVED_PATHS = [
6
+ 'app/controllers/profile_controller.rb',
7
+ 'app/controllers/password_controller.rb',
8
+ 'app/components/nav_link_component.rb',
9
+ 'app/components/responsive_nav_link_component.rb',
10
+ 'app/views/layouts/_navigation.html.erb',
11
+ 'app/views/profile/destroy.turbo_stream.erb',
12
+ 'app/views/profile/edit.html.erb',
13
+ 'app/views/profile/partials/_confirm_user_deletion_modal.html.erb',
14
+ 'app/views/profile/partials/_delete_user_form.html.erb',
15
+ 'app/views/profile/partials/_update_appearance_form.html.erb',
16
+ 'app/views/profile/partials/_update_password_form.html.erb',
17
+ 'app/views/profile/partials/_update_profile_information_form.html.erb'
18
+ ].freeze
19
+
2
20
  def install
3
21
  # Gems...
4
22
  return unless remove_gems([ 'sprockets-rails', 'stimulus-rails' ])
@@ -1,4 +1,27 @@
1
1
  class Kaze::Commands::App::InertiaReactStack < Kaze::Commands::App::BaseStack
2
+ # Paths that earlier versions of Kaze installed here and this version no longer
3
+ # ships. `kaze upgrade` offers to delete whichever of them an application still
4
+ # has; anything removed in a future version belongs on this list too.
5
+ REMOVED_PATHS = [
6
+ 'app/controllers/profile_controller.rb',
7
+ 'app/controllers/password_controller.rb',
8
+ 'app/javascript/Components/Checkbox.tsx',
9
+ 'app/javascript/Components/DangerButton.tsx',
10
+ 'app/javascript/Components/Dropdown.tsx',
11
+ 'app/javascript/Components/InputLabel.tsx',
12
+ 'app/javascript/Components/Modal.tsx',
13
+ 'app/javascript/Components/NavLink.tsx',
14
+ 'app/javascript/Components/PrimaryButton.tsx',
15
+ 'app/javascript/Components/ResponsiveNavLink.tsx',
16
+ 'app/javascript/Components/SecondaryButton.tsx',
17
+ 'app/javascript/Components/TextInput.tsx',
18
+ 'app/javascript/Pages/Profile/Edit.tsx',
19
+ 'app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx',
20
+ 'app/javascript/Pages/Profile/Partials/UpdateAppearanceForm.tsx',
21
+ 'app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx',
22
+ 'app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx'
23
+ ].freeze
24
+
2
25
  def install
3
26
  # Gems...
4
27
  return unless remove_gems([ 'sprockets-rails', 'turbo-rails', 'stimulus-rails' ])
@@ -1,4 +1,28 @@
1
1
  class Kaze::Commands::App::InertiaVueStack < Kaze::Commands::App::BaseStack
2
+ # Paths that earlier versions of Kaze installed here and this version no longer
3
+ # ships. `kaze upgrade` offers to delete whichever of them an application still
4
+ # has; anything removed in a future version belongs on this list too.
5
+ REMOVED_PATHS = [
6
+ 'app/controllers/profile_controller.rb',
7
+ 'app/controllers/password_controller.rb',
8
+ 'app/javascript/Components/Checkbox.vue',
9
+ 'app/javascript/Components/DangerButton.vue',
10
+ 'app/javascript/Components/Dropdown.vue',
11
+ 'app/javascript/Components/DropdownLink.vue',
12
+ 'app/javascript/Components/InputLabel.vue',
13
+ 'app/javascript/Components/Modal.vue',
14
+ 'app/javascript/Components/NavLink.vue',
15
+ 'app/javascript/Components/PrimaryButton.vue',
16
+ 'app/javascript/Components/ResponsiveNavLink.vue',
17
+ 'app/javascript/Components/SecondaryButton.vue',
18
+ 'app/javascript/Components/TextInput.vue',
19
+ 'app/javascript/Pages/Profile/Edit.vue',
20
+ 'app/javascript/Pages/Profile/Partials/DeleteUserForm.vue',
21
+ 'app/javascript/Pages/Profile/Partials/UpdateAppearanceForm.vue',
22
+ 'app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue',
23
+ 'app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue'
24
+ ].freeze
25
+
2
26
  def install
3
27
  # Gems...
4
28
  return unless remove_gems([ 'sprockets-rails', 'turbo-rails', 'stimulus-rails' ])
@@ -7,10 +7,7 @@ class Kaze::Commands::App < Thor
7
7
 
8
8
  desc 'install [STACK]', 'Install the Kaze controllers and resources. Supported stacks: hotwire, react, vue.'
9
9
  def install(stack = 'hotwire')
10
- unless File.exist?("#{Dir.pwd}/bin/rails")
11
- say 'Kaze must be run in a new Rails application.', :red
12
- exit 1
13
- end
10
+ ensure_rails_application
14
11
 
15
12
  # The stack installers stop at the first step that fails, so a falsy return
16
13
  # means the application is half-installed. Exiting non-zero keeps that from
@@ -21,8 +18,56 @@ class Kaze::Commands::App < Thor
21
18
  exit 1
22
19
  end
23
20
 
21
+ desc 'upgrade [STACK]', 'Remove files an earlier Kaze installed that this version no longer ships, then install.'
22
+ method_option :force, type: :boolean, default: false, aliases: '-f', desc: 'Skip the confirmation prompt.'
23
+ method_option :'dry-run', type: :boolean, default: false, desc: 'List what would be removed and stop.'
24
+ def upgrade(stack = 'hotwire')
25
+ ensure_rails_application
26
+
27
+ stack = StackFactory.make(stack.to_sym)
28
+ paths = stack.removable_paths
29
+
30
+ if paths.empty?
31
+ say 'Nothing to remove. This application has none of the files earlier versions installed.', :green
32
+ else
33
+ say "Kaze no longer ships #{paths.length} #{paths.length == 1 ? 'file' : 'files'} this application still has:", :yellow
34
+ say ''
35
+ paths.each { |path| say " #{path}" }
36
+ say ''
37
+ say 'They are yours now, so check for your own changes before agreeing.', :yellow
38
+
39
+ return if options[:'dry-run']
40
+
41
+ unless options[:force] || yes?('Remove them? [y/N]')
42
+ say 'Nothing was removed.', :red
43
+ exit 1
44
+ end
45
+
46
+ stack.remove_paths(paths)
47
+
48
+ say ''
49
+ say "Removed #{paths.length} #{paths.length == 1 ? 'file' : 'files'}.", :green
50
+ say ''
51
+ end
52
+
53
+ return if options[:'dry-run']
54
+
55
+ exit 1 unless stack.install
56
+ rescue => e
57
+ say e.message, :red
58
+ exit 1
59
+ end
60
+
24
61
  desc 'version', 'Show Kaze version'
25
62
  def version
26
63
  puts Kaze::VERSION
27
64
  end
65
+
66
+ private
67
+ def ensure_rails_application
68
+ return if File.exist?("#{Dir.pwd}/bin/rails")
69
+
70
+ say 'Kaze must be run in a new Rails application.', :red
71
+ exit 1
72
+ end
28
73
  end
data/lib/kaze/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kaze
2
- VERSION = '2.0.1'
2
+ VERSION = '2.1.1'
3
3
  end
@@ -12,7 +12,7 @@
12
12
  </div>
13
13
  <div class="flex items-center justify-end mt-4">
14
14
  <%= render(PrimaryButtonComponent.new) do %>
15
- Email Password Reset Link
15
+ Email password reset link
16
16
  <% end %>
17
17
  </div>
18
18
  <% end %>
@@ -25,7 +25,7 @@
25
25
  Forgot your password?
26
26
  </a>
27
27
  <%= render(PrimaryButtonComponent.new({ class: "ms-4" })) do %>
28
- Login
28
+ Log in
29
29
  <% end %>
30
30
  </div>
31
31
  <% end %>
@@ -17,9 +17,9 @@
17
17
  <%= render(TextInputComponent.new({ id: "password", class: "block mt-1 w-full", type: "password", name: "password", required: true, autocomplete: "new-password" })) %>
18
18
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password] })) %>
19
19
  </div>
20
- <!-- Confirm Password -->
20
+ <!-- Confirm password -->
21
21
  <div class="mt-4">
22
- <%= render(InputLabelComponent.new({ for: "password_confirmation", value: "Confirm Password" })) %>
22
+ <%= render(InputLabelComponent.new({ for: "password_confirmation", value: "Confirm password" })) %>
23
23
  <%= render(TextInputComponent.new({ id: "password_confirmation", class: "block mt-1 w-full", type: "password", name: "password_confirmation", required: true, autocomplete: "new-password" })) %>
24
24
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password_confirmation] })) %>
25
25
  </div>
@@ -7,15 +7,15 @@
7
7
  <%= render(TextInputComponent.new({ id: "password", class: "block mt-1 w-full", type: "password", name: "password", required: true, autofocus: true, autocomplete: "new-password" })) %>
8
8
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password] })) %>
9
9
  </div>
10
- <!-- Confirm Password -->
10
+ <!-- Confirm password -->
11
11
  <div class="mt-4">
12
- <%= render(InputLabelComponent.new({ for: "password_confirmation", value: "Confirm Password" })) %>
12
+ <%= render(InputLabelComponent.new({ for: "password_confirmation", value: "Confirm password" })) %>
13
13
  <%= render(TextInputComponent.new({ id: "password_confirmation", class: "block mt-1 w-full", type: "password", name: "password_confirmation", required: true, autocomplete: "new-password" })) %>
14
14
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @form.error_messages[:password_confirmation] })) %>
15
15
  </div>
16
16
  <div class="flex items-center justify-end mt-4">
17
17
  <%= render(PrimaryButtonComponent.new) do %>
18
- Reset Password
18
+ Reset password
19
19
  <% end %>
20
20
  </div>
21
21
  <% end %>
@@ -10,14 +10,14 @@
10
10
  <form method="POST" action="<%= verification_send_path %>">
11
11
  <div>
12
12
  <%= render(PrimaryButtonComponent.new) do %>
13
- Resend Verification Email
13
+ Resend verification email
14
14
  <% end %>
15
15
  </div>
16
16
  </form>
17
17
  <form method="POST" action="<%= logout_path %>">
18
18
  <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
19
19
  <button type="submit" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800">
20
- Log Out
20
+ Log out
21
21
  </button>
22
22
  </form>
23
23
  </div>
@@ -28,7 +28,7 @@
28
28
  <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
29
29
  <%= render(DropdownLinkComponent.new({ href: logout_path, onclick: "event.preventDefault();this.closest('form').submit()" })) do %>
30
30
  <%= render(IconComponent.new('log-out')) %>
31
- Log Out
31
+ Log out
32
32
  <% end %>
33
33
  </form>
34
34
  <% end %>
@@ -1,21 +1,21 @@
1
1
  <%= turbo_frame_tag 'update_password_form' do %>
2
2
  <section>
3
3
  <%= form_with model: @update_password_form, url: password_update_path, method: "put", class: "mt-6 space-y-6" do |update_password_form| %>
4
- <!-- Current Password -->
4
+ <!-- Current password -->
5
5
  <div>
6
- <%= render(InputLabelComponent.new({ for: "update_password_current_password", value: "Current Password" })) %>
6
+ <%= render(InputLabelComponent.new({ for: "update_password_current_password", value: "Current password" })) %>
7
7
  <%= render(TextInputComponent.new({ id: "update_password_current_password", class: "block mt-1 w-full", type: "password", name: "current_password", autocomplete: "current-password" })) %>
8
8
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @update_password_form.error_messages[:current_password] })) %>
9
9
  </div>
10
- <!-- New Password -->
10
+ <!-- New password -->
11
11
  <div>
12
- <%= render(InputLabelComponent.new({ for: "update_password_password", value: "New Password" })) %>
12
+ <%= render(InputLabelComponent.new({ for: "update_password_password", value: "New password" })) %>
13
13
  <%= render(TextInputComponent.new({ id: "update_password_password", class: "block mt-1 w-full", type: "password", name: "password", autocomplete: "new-password" })) %>
14
14
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @update_password_form.error_messages[:password] })) %>
15
15
  </div>
16
- <!-- Confirm Password -->
16
+ <!-- Confirm password -->
17
17
  <div class="mt-4">
18
- <%= render(InputLabelComponent.new({ for: "update_password_password_confirmation", value: "Confirm Password" })) %>
18
+ <%= render(InputLabelComponent.new({ for: "update_password_password_confirmation", value: "Confirm password" })) %>
19
19
  <%= render(TextInputComponent.new({ id: "update_password_password_confirmation", class: "block mt-1 w-full", type: "password", name: "password_confirmation", autocomplete: "new-password" })) %>
20
20
  <%= render(InputErrorComponent.new({ class: "mt-2", message: @update_password_form.error_messages[:password_confirmation] })) %>
21
21
  </div>
@@ -17,7 +17,7 @@
17
17
  Cancel
18
18
  <% end %>
19
19
  <%= render(DangerButtonComponent.new({ class: "ms-3" })) do %>
20
- Delete Account
20
+ Delete account
21
21
  <% end %>
22
22
  </div>
23
23
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <section class="space-y-6">
2
2
  <%= render(DangerButtonComponent.new({"x-data": "", "x-on:click.prevent": "$dispatch('open-modal', 'confirm-user-deletion')"})) do %>
3
- Delete Account
3
+ Delete account
4
4
  <% end %>
5
5
  </section>
6
6
  <%= render 'settings/profile/confirm_user_deletion_modal' %>
@@ -19,7 +19,7 @@ export default function ForgotPassword({ status }: { status?: string }) {
19
19
 
20
20
  return (
21
21
  <GuestLayout>
22
- <Head title="Forgot Password" />
22
+ <Head title="Forgot password" />
23
23
 
24
24
  <div className="mb-4 text-sm text-gray-600 dark:text-gray-400">
25
25
  Forgot your password? No problem. Just let us know your email address and we will email you a password reset
@@ -43,7 +43,7 @@ export default function ForgotPassword({ status }: { status?: string }) {
43
43
 
44
44
  <div className="flex items-center justify-end mt-4">
45
45
  <Button className="ms-4" disabled={processing}>
46
- Email Password Reset Link
46
+ Email password reset link
47
47
  </Button>
48
48
  </div>
49
49
  </form>
@@ -80,7 +80,7 @@ export default function Register() {
80
80
  </div>
81
81
 
82
82
  <div className="mt-4">
83
- <Label htmlFor="password_confirmation">Confirm Password</Label>
83
+ <Label htmlFor="password_confirmation">Confirm password</Label>
84
84
 
85
85
  <Input
86
86
  id="password_confirmation"
@@ -24,7 +24,7 @@ export default function ResetPassword({ token }: { token: string }) {
24
24
 
25
25
  return (
26
26
  <GuestLayout>
27
- <Head title="Reset Password" />
27
+ <Head title="Reset password" />
28
28
 
29
29
  <form onSubmit={submit}>
30
30
  <div>
@@ -45,7 +45,7 @@ export default function ResetPassword({ token }: { token: string }) {
45
45
  </div>
46
46
 
47
47
  <div className="mt-4">
48
- <Label htmlFor="password_confirmation">Confirm Password</Label>
48
+ <Label htmlFor="password_confirmation">Confirm password</Label>
49
49
 
50
50
  <Input
51
51
  type="password"
@@ -61,7 +61,7 @@ export default function ResetPassword({ token }: { token: string }) {
61
61
 
62
62
  <div className="flex items-center justify-end mt-4">
63
63
  <Button className="ms-4" disabled={processing}>
64
- Reset Password
64
+ Reset password
65
65
  </Button>
66
66
  </div>
67
67
  </form>
@@ -15,7 +15,7 @@ export default function VerifyEmail({ status }: { status?: string }) {
15
15
 
16
16
  return (
17
17
  <GuestLayout>
18
- <Head title="Email Verification" />
18
+ <Head title="Email verification" />
19
19
 
20
20
  <div className="mb-4 text-sm text-gray-600 dark:text-gray-400">
21
21
  Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we
@@ -30,7 +30,7 @@ export default function VerifyEmail({ status }: { status?: string }) {
30
30
 
31
31
  <form onSubmit={submit}>
32
32
  <div className="mt-4 flex items-center justify-between">
33
- <Button disabled={processing}>Resend Verification Email</Button>
33
+ <Button disabled={processing}>Resend verification email</Button>
34
34
 
35
35
  <Link
36
36
  href={logout_path()}
@@ -38,7 +38,7 @@ export default function VerifyEmail({ status }: { status?: string }) {
38
38
  as="button"
39
39
  className="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"
40
40
  >
41
- Log Out
41
+ Log out
42
42
  </Link>
43
43
  </div>
44
44
  </form>
@@ -55,7 +55,7 @@ export default function DeleteUserForm({ className = '' }: { className?: string
55
55
  return (
56
56
  <section className={`space-y-6 ${className}`}>
57
57
  <Button variant="destructive" onClick={confirmUserDeletion}>
58
- Delete Account
58
+ Delete account
59
59
  </Button>
60
60
 
61
61
  <Dialog open={confirmingUserDeletion} onOpenChange={(open) => !open && closeModal()}>
@@ -96,7 +96,7 @@ export default function DeleteUserForm({ className = '' }: { className?: string
96
96
  </Button>
97
97
 
98
98
  <Button variant="destructive" disabled={processing}>
99
- Delete Account
99
+ Delete account
100
100
  </Button>
101
101
  </DialogFooter>
102
102
  </form>
@@ -41,7 +41,7 @@ export default function UpdatePasswordForm({ className = '' }: { className?: str
41
41
  <section className={className}>
42
42
  <form onSubmit={updatePassword} className="space-y-6">
43
43
  <div>
44
- <Label htmlFor="current_password">Current Password</Label>
44
+ <Label htmlFor="current_password">Current password</Label>
45
45
 
46
46
  <Input
47
47
  id="current_password"
@@ -57,7 +57,7 @@ export default function UpdatePasswordForm({ className = '' }: { className?: str
57
57
  </div>
58
58
 
59
59
  <div>
60
- <Label htmlFor="password">New Password</Label>
60
+ <Label htmlFor="password">New password</Label>
61
61
 
62
62
  <Input
63
63
  id="password"
@@ -73,7 +73,7 @@ export default function UpdatePasswordForm({ className = '' }: { className?: str
73
73
  </div>
74
74
 
75
75
  <div>
76
- <Label htmlFor="password_confirmation">Confirm Password</Label>
76
+ <Label htmlFor="password_confirmation">Confirm password</Label>
77
77
 
78
78
  <Input
79
79
  id="password_confirmation"
@@ -22,7 +22,7 @@ const submit = () => {
22
22
 
23
23
  <template>
24
24
  <GuestLayout>
25
- <Head title="Forgot Password" />
25
+ <Head title="Forgot password" />
26
26
 
27
27
  <div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
28
28
  Forgot your password? No problem. Just let us know your email address and we will email you a password reset link
@@ -52,7 +52,7 @@ const submit = () => {
52
52
 
53
53
  <div class="flex items-center justify-end mt-4">
54
54
  <Button :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
55
- Email Password Reset Link
55
+ Email password reset link
56
56
  </Button>
57
57
  </div>
58
58
  </form>
@@ -75,7 +75,7 @@ const submit = () => {
75
75
  </div>
76
76
 
77
77
  <div class="mt-4">
78
- <Label for="password_confirmation">Confirm Password</Label>
78
+ <Label for="password_confirmation">Confirm password</Label>
79
79
 
80
80
  <Input
81
81
  id="password_confirmation"
@@ -28,7 +28,7 @@ const submit = () => {
28
28
 
29
29
  <template>
30
30
  <GuestLayout>
31
- <Head title="Reset Password" />
31
+ <Head title="Reset password" />
32
32
 
33
33
  <form @submit.prevent="submit">
34
34
  <div>
@@ -48,7 +48,7 @@ const submit = () => {
48
48
  </div>
49
49
 
50
50
  <div class="mt-4">
51
- <Label for="password_confirmation">Confirm Password</Label>
51
+ <Label for="password_confirmation">Confirm password</Label>
52
52
 
53
53
  <Input
54
54
  id="password_confirmation"
@@ -63,7 +63,7 @@ const submit = () => {
63
63
  </div>
64
64
 
65
65
  <div class="flex items-center justify-end mt-4">
66
- <Button :class="{ 'opacity-25': form.processing }" :disabled="form.processing"> Reset Password </Button>
66
+ <Button :class="{ 'opacity-25': form.processing }" :disabled="form.processing"> Reset password </Button>
67
67
  </div>
68
68
  </form>
69
69
  </GuestLayout>
@@ -20,7 +20,7 @@ const verificationLinkSent = computed(() => props.status === 'verification-link-
20
20
 
21
21
  <template>
22
22
  <GuestLayout>
23
- <Head title="Email Verification" />
23
+ <Head title="Email verification" />
24
24
 
25
25
  <div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
26
26
  Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just
@@ -34,7 +34,7 @@ const verificationLinkSent = computed(() => props.status === 'verification-link-
34
34
  <form @submit.prevent="submit">
35
35
  <div class="mt-4 flex items-center justify-between">
36
36
  <Button :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
37
- Resend Verification Email
37
+ Resend verification email
38
38
  </Button>
39
39
 
40
40
  <Link
@@ -42,7 +42,7 @@ const verificationLinkSent = computed(() => props.status === 'verification-link-
42
42
  method="post"
43
43
  as="button"
44
44
  class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"
45
- >Log Out</Link
45
+ >Log out</Link
46
46
  >
47
47
  </div>
48
48
  </form>
@@ -49,7 +49,7 @@ const closeModal = () => {
49
49
 
50
50
  <template>
51
51
  <section class="space-y-6">
52
- <Button variant="destructive" @click="confirmUserDeletion">Delete Account</Button>
52
+ <Button variant="destructive" @click="confirmUserDeletion">Delete account</Button>
53
53
 
54
54
  <Dialog v-model:open="confirmingUserDeletion">
55
55
  <DialogContent>
@@ -87,7 +87,7 @@ const closeModal = () => {
87
87
  :disabled="form.processing"
88
88
  @click="deleteUser"
89
89
  >
90
- Delete Account
90
+ Delete account
91
91
  </Button>
92
92
  </DialogFooter>
93
93
  </DialogContent>
@@ -40,7 +40,7 @@ const updatePassword = () => {
40
40
  <section>
41
41
  <form @submit.prevent="updatePassword" class="space-y-6">
42
42
  <div>
43
- <Label for="current_password">Current Password</Label>
43
+ <Label for="current_password">Current password</Label>
44
44
 
45
45
  <Input
46
46
  id="current_password"
@@ -55,7 +55,7 @@ const updatePassword = () => {
55
55
  </div>
56
56
 
57
57
  <div>
58
- <Label for="password">New Password</Label>
58
+ <Label for="password">New password</Label>
59
59
 
60
60
  <Input
61
61
  id="password"
@@ -70,7 +70,7 @@ const updatePassword = () => {
70
70
  </div>
71
71
 
72
72
  <div>
73
- <Label for="password_confirmation">Confirm Password</Label>
73
+ <Label for="password_confirmation">Confirm password</Label>
74
74
 
75
75
  <Input
76
76
  id="password_confirmation"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kaze
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cuong Giang
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '2.6'
40
+ - !ruby/object:Gem::Dependency
41
+ name: minitest
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '5.0'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: railties
42
56
  requirement: !ruby/object:Gem::Requirement