kaze 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +42 -0
  4. data/bin/kaze +11 -0
  5. data/lib/kaze/commands/install_command.rb +63 -0
  6. data/lib/kaze/commands/install_inertia_stacks.rb +151 -0
  7. data/lib/kaze/commands.rb +2 -0
  8. data/lib/kaze/version.rb +3 -0
  9. data/lib/kaze.rb +9 -0
  10. data/stubs/default/Procfile.dev +3 -0
  11. data/stubs/default/app/assets/stylesheets/application.css +1 -0
  12. data/stubs/default/app/assets/stylesheets/application.tailwind.css +3 -0
  13. data/stubs/default/app/controllers/application_controller.rb +5 -0
  14. data/stubs/default/app/controllers/auth/authenticated_session_controller.rb +28 -0
  15. data/stubs/default/app/controllers/auth/new_password_controller.rb +18 -0
  16. data/stubs/default/app/controllers/auth/password_reset_link_controller.rb +17 -0
  17. data/stubs/default/app/controllers/auth/registered_user_controller.rb +19 -0
  18. data/stubs/default/app/controllers/concerns/authenticate.rb +34 -0
  19. data/stubs/default/app/controllers/concerns/handle_inertia_requests.rb +9 -0
  20. data/stubs/default/app/controllers/concerns/verify_csrf_token.rb +24 -0
  21. data/stubs/default/app/controllers/dashboard_controller.rb +5 -0
  22. data/stubs/default/app/controllers/password_controller.rb +11 -0
  23. data/stubs/default/app/controllers/profile_controller.rb +31 -0
  24. data/stubs/default/app/controllers/welcome_controller.rb +10 -0
  25. data/stubs/default/app/forms/application_form.rb +9 -0
  26. data/stubs/default/app/forms/auth/login_form.rb +18 -0
  27. data/stubs/default/app/forms/auth/new_password_form.rb +21 -0
  28. data/stubs/default/app/forms/auth/register_form.rb +7 -0
  29. data/stubs/default/app/forms/auth/send_password_reset_link_form.rb +22 -0
  30. data/stubs/default/app/forms/delete_user_form.rb +5 -0
  31. data/stubs/default/app/forms/update_password_form.rb +6 -0
  32. data/stubs/default/app/forms/update_profile_information_form.rb +6 -0
  33. data/stubs/default/app/mailers/application_mailer.rb +11 -0
  34. data/stubs/default/app/mailers/user_mailer.rb +8 -0
  35. data/stubs/default/app/models/application_record.rb +3 -0
  36. data/stubs/default/app/models/concerns/can_reset_password.rb +5 -0
  37. data/stubs/default/app/models/current.rb +3 -0
  38. data/stubs/default/app/models/user.rb +11 -0
  39. data/stubs/default/app/validators/current_password_validator.rb +5 -0
  40. data/stubs/default/app/validators/email_validator.rb +7 -0
  41. data/stubs/default/app/validators/lowercase_validator.rb +5 -0
  42. data/stubs/default/app/validators/uniqueness_validator.rb +24 -0
  43. data/stubs/default/app/views/layouts/mailer.html.erb +374 -0
  44. data/stubs/default/app/views/layouts/mailer.text.erb +11 -0
  45. data/stubs/default/app/views/user_mailer/reset_password.html.erb +39 -0
  46. data/stubs/default/bin/dev +16 -0
  47. data/stubs/default/bin/vite +27 -0
  48. data/stubs/default/config/routes.rb +27 -0
  49. data/stubs/default/config/vite.json +16 -0
  50. data/stubs/default/db/migrate/20240101000000_create_users.rb +14 -0
  51. data/stubs/default/db/migrate/20240101000001_create_delayed_jobs.rb +22 -0
  52. data/stubs/inertia-react-ts/app/javascript/Components/ApplicationLogo.tsx +12 -0
  53. data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +14 -0
  54. data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +17 -0
  55. data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +99 -0
  56. data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +9 -0
  57. data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +9 -0
  58. data/stubs/inertia-react-ts/app/javascript/Components/Modal.tsx +68 -0
  59. data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +18 -0
  60. data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +17 -0
  61. data/stubs/inertia-react-ts/app/javascript/Components/ResponsiveNavLink.tsx +16 -0
  62. data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +18 -0
  63. data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +30 -0
  64. data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +131 -0
  65. data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +19 -0
  66. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +52 -0
  67. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +98 -0
  68. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +118 -0
  69. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +74 -0
  70. data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +22 -0
  71. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +33 -0
  72. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +100 -0
  73. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.tsx +114 -0
  74. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.tsx +84 -0
  75. data/stubs/inertia-react-ts/app/javascript/Pages/Welcome.tsx +66 -0
  76. data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +34 -0
  77. data/stubs/inertia-react-ts/app/javascript/entrypoints/bootstrap.ts +4 -0
  78. data/stubs/inertia-react-ts/app/javascript/types/global.d.ts +7 -0
  79. data/stubs/inertia-react-ts/app/javascript/types/index.d.ts +12 -0
  80. data/stubs/inertia-react-ts/app/javascript/types/vite-env.d.ts +1 -0
  81. data/stubs/inertia-react-ts/app/views/layouts/application.html.erb +26 -0
  82. data/stubs/inertia-react-ts/config/tailwind.config.js +22 -0
  83. data/stubs/inertia-react-ts/package.json +26 -0
  84. data/stubs/inertia-react-ts/tsconfig.json +19 -0
  85. data/stubs/inertia-react-ts/vite.config.ts +13 -0
  86. data/stubs/inertia-vue-ts/app/javascript/Components/ApplicationLogo.vue +8 -0
  87. data/stubs/inertia-vue-ts/app/javascript/Components/Checkbox.vue +29 -0
  88. data/stubs/inertia-vue-ts/app/javascript/Components/DangerButton.vue +7 -0
  89. data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +75 -0
  90. data/stubs/inertia-vue-ts/app/javascript/Components/DropdownLink.vue +16 -0
  91. data/stubs/inertia-vue-ts/app/javascript/Components/InputError.vue +13 -0
  92. data/stubs/inertia-vue-ts/app/javascript/Components/InputLabel.vue +12 -0
  93. data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +96 -0
  94. data/stubs/inertia-vue-ts/app/javascript/Components/NavLink.vue +21 -0
  95. data/stubs/inertia-vue-ts/app/javascript/Components/PrimaryButton.vue +7 -0
  96. data/stubs/inertia-vue-ts/app/javascript/Components/ResponsiveNavLink.vue +21 -0
  97. data/stubs/inertia-vue-ts/app/javascript/Components/SecondaryButton.vue +19 -0
  98. data/stubs/inertia-vue-ts/app/javascript/Components/TextInput.vue +23 -0
  99. data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +155 -0
  100. data/stubs/inertia-vue-ts/app/javascript/Layouts/GuestLayout.vue +20 -0
  101. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +60 -0
  102. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +93 -0
  103. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +106 -0
  104. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +89 -0
  105. data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +22 -0
  106. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +42 -0
  107. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +98 -0
  108. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdatePasswordForm.vue +108 -0
  109. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdateProfileInformationForm.vue +78 -0
  110. data/stubs/inertia-vue-ts/app/javascript/Pages/Welcome.vue +56 -0
  111. data/stubs/inertia-vue-ts/app/javascript/entrypoints/application.ts +34 -0
  112. data/stubs/inertia-vue-ts/app/javascript/entrypoints/bootstrap.ts +4 -0
  113. data/stubs/inertia-vue-ts/app/javascript/types/global.d.ts +13 -0
  114. data/stubs/inertia-vue-ts/app/javascript/types/index.d.ts +12 -0
  115. data/stubs/inertia-vue-ts/app/javascript/types/vite-env.d.ts +1 -0
  116. data/stubs/inertia-vue-ts/app/views/layouts/application.html.erb +25 -0
  117. data/stubs/inertia-vue-ts/config/tailwind.config.js +22 -0
  118. data/stubs/inertia-vue-ts/package.json +24 -0
  119. data/stubs/inertia-vue-ts/tsconfig.json +19 -0
  120. data/stubs/inertia-vue-ts/vite.config.ts +13 -0
  121. metadata +205 -0
@@ -0,0 +1,98 @@
1
+ <script setup lang="ts">
2
+ import DangerButton from '@/Components/DangerButton.vue';
3
+ import InputError from '@/Components/InputError.vue';
4
+ import InputLabel from '@/Components/InputLabel.vue';
5
+ import Modal from '@/Components/Modal.vue';
6
+ import SecondaryButton from '@/Components/SecondaryButton.vue';
7
+ import TextInput from '@/Components/TextInput.vue';
8
+ import { useForm } from '@inertiajs/vue3';
9
+ import { nextTick, ref } from 'vue';
10
+ import { profile_destroy_path } from '@/routes';
11
+
12
+ const confirmingUserDeletion = ref(false);
13
+ const passwordInput = ref<HTMLInputElement | null>(null);
14
+
15
+ const form = useForm({
16
+ password: '',
17
+ });
18
+
19
+ const confirmUserDeletion = () => {
20
+ confirmingUserDeletion.value = true;
21
+
22
+ nextTick(() => passwordInput.value?.focus());
23
+ };
24
+
25
+ const deleteUser = () => {
26
+ form.delete(profile_destroy_path(), {
27
+ preserveScroll: true,
28
+ onSuccess: () => closeModal(),
29
+ onError: () => passwordInput.value?.focus(),
30
+ onFinish: () => {
31
+ form.reset();
32
+ },
33
+ });
34
+ };
35
+
36
+ const closeModal = () => {
37
+ confirmingUserDeletion.value = false;
38
+
39
+ form.reset();
40
+ };
41
+ </script>
42
+
43
+ <template>
44
+ <section class="space-y-6">
45
+ <header>
46
+ <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Delete Account</h2>
47
+
48
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
49
+ Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting
50
+ your account, please download any data or information that you wish to retain.
51
+ </p>
52
+ </header>
53
+
54
+ <DangerButton @click="confirmUserDeletion">Delete Account</DangerButton>
55
+
56
+ <Modal :show="confirmingUserDeletion" @close="closeModal">
57
+ <div class="p-6">
58
+ <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
59
+ Are you sure you want to delete your account?
60
+ </h2>
61
+
62
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
63
+ Once your account is deleted, all of its resources and data will be permanently deleted. Please
64
+ enter your password to confirm you would like to permanently delete your account.
65
+ </p>
66
+
67
+ <div class="mt-6">
68
+ <InputLabel for="password" value="Password" class="sr-only" />
69
+
70
+ <TextInput
71
+ id="password"
72
+ ref="passwordInput"
73
+ v-model="form.password"
74
+ type="password"
75
+ class="mt-1 block w-3/4"
76
+ placeholder="Password"
77
+ @keyup.enter="deleteUser"
78
+ />
79
+
80
+ <InputError :message="form.errors.password" class="mt-2" />
81
+ </div>
82
+
83
+ <div class="mt-6 flex justify-end">
84
+ <SecondaryButton @click="closeModal"> Cancel </SecondaryButton>
85
+
86
+ <DangerButton
87
+ class="ms-3"
88
+ :class="{ 'opacity-25': form.processing }"
89
+ :disabled="form.processing"
90
+ @click="deleteUser"
91
+ >
92
+ Delete Account
93
+ </DangerButton>
94
+ </div>
95
+ </div>
96
+ </Modal>
97
+ </section>
98
+ </template>
@@ -0,0 +1,108 @@
1
+ <script setup lang="ts">
2
+ import InputError from '@/Components/InputError.vue';
3
+ import InputLabel from '@/Components/InputLabel.vue';
4
+ import PrimaryButton from '@/Components/PrimaryButton.vue';
5
+ import TextInput from '@/Components/TextInput.vue';
6
+ import { useForm } from '@inertiajs/vue3';
7
+ import { ref } from 'vue';
8
+ import { password_update_path } from '@/routes';
9
+
10
+ const passwordInput = ref<HTMLInputElement | null>(null);
11
+ const currentPasswordInput = ref<HTMLInputElement | null>(null);
12
+
13
+ const form = useForm({
14
+ current_password: '',
15
+ password: '',
16
+ password_confirmation: '',
17
+ });
18
+
19
+ const updatePassword = () => {
20
+ form.put(password_update_path(), {
21
+ preserveScroll: true,
22
+ onSuccess: () => {
23
+ form.reset();
24
+ },
25
+ onError: () => {
26
+ if (form.errors.password) {
27
+ form.reset('password', 'password_confirmation');
28
+ passwordInput.value?.focus();
29
+ }
30
+ if (form.errors.current_password) {
31
+ form.reset('current_password');
32
+ currentPasswordInput.value?.focus();
33
+ }
34
+ },
35
+ });
36
+ };
37
+ </script>
38
+
39
+ <template>
40
+ <section>
41
+ <header>
42
+ <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Update Password</h2>
43
+
44
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
45
+ Ensure your account is using a long, random password to stay secure.
46
+ </p>
47
+ </header>
48
+
49
+ <form @submit.prevent="updatePassword" class="mt-6 space-y-6">
50
+ <div>
51
+ <InputLabel for="current_password" value="Current Password" />
52
+
53
+ <TextInput
54
+ id="current_password"
55
+ ref="currentPasswordInput"
56
+ v-model="form.current_password"
57
+ type="password"
58
+ class="mt-1 block w-full"
59
+ autocomplete="current-password"
60
+ />
61
+
62
+ <InputError :message="form.errors.current_password" class="mt-2" />
63
+ </div>
64
+
65
+ <div>
66
+ <InputLabel for="password" value="New Password" />
67
+
68
+ <TextInput
69
+ id="password"
70
+ ref="passwordInput"
71
+ v-model="form.password"
72
+ type="password"
73
+ class="mt-1 block w-full"
74
+ autocomplete="new-password"
75
+ />
76
+
77
+ <InputError :message="form.errors.password" class="mt-2" />
78
+ </div>
79
+
80
+ <div>
81
+ <InputLabel for="password_confirmation" value="Confirm Password" />
82
+
83
+ <TextInput
84
+ id="password_confirmation"
85
+ v-model="form.password_confirmation"
86
+ type="password"
87
+ class="mt-1 block w-full"
88
+ autocomplete="new-password"
89
+ />
90
+
91
+ <InputError :message="form.errors.password_confirmation" class="mt-2" />
92
+ </div>
93
+
94
+ <div class="flex items-center gap-4">
95
+ <PrimaryButton :disabled="form.processing">Save</PrimaryButton>
96
+
97
+ <Transition
98
+ enter-active-class="transition ease-in-out"
99
+ enter-from-class="opacity-0"
100
+ leave-active-class="transition ease-in-out"
101
+ leave-to-class="opacity-0"
102
+ >
103
+ <p v-if="form.recentlySuccessful" class="text-sm text-gray-600 dark:text-gray-400">Saved.</p>
104
+ </Transition>
105
+ </div>
106
+ </form>
107
+ </section>
108
+ </template>
@@ -0,0 +1,78 @@
1
+ <script setup lang="ts">
2
+ import InputError from '@/Components/InputError.vue';
3
+ import InputLabel from '@/Components/InputLabel.vue';
4
+ import PrimaryButton from '@/Components/PrimaryButton.vue';
5
+ import TextInput from '@/Components/TextInput.vue';
6
+ import { Link, useForm, usePage } from '@inertiajs/vue3';
7
+ import { profile_update_path } from '@/routes';
8
+
9
+ defineProps<{
10
+ mustVerifyEmail?: Boolean;
11
+ status?: String;
12
+ }>();
13
+
14
+ const user = usePage().props.auth.user;
15
+
16
+ const form = useForm({
17
+ name: user.name,
18
+ email: user.email,
19
+ });
20
+ </script>
21
+
22
+ <template>
23
+ <section>
24
+ <header>
25
+ <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Profile Information</h2>
26
+
27
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
28
+ Update your account's profile information and email address.
29
+ </p>
30
+ </header>
31
+
32
+ <form @submit.prevent="form.patch(profile_update_path())" class="mt-6 space-y-6">
33
+ <div>
34
+ <InputLabel for="name" value="Name" />
35
+
36
+ <TextInput
37
+ id="name"
38
+ type="text"
39
+ class="mt-1 block w-full"
40
+ v-model="form.name"
41
+ required
42
+ autofocus
43
+ autocomplete="name"
44
+ />
45
+
46
+ <InputError class="mt-2" :message="form.errors.name" />
47
+ </div>
48
+
49
+ <div>
50
+ <InputLabel for="email" value="Email" />
51
+
52
+ <TextInput
53
+ id="email"
54
+ type="email"
55
+ class="mt-1 block w-full"
56
+ v-model="form.email"
57
+ required
58
+ autocomplete="username"
59
+ />
60
+
61
+ <InputError class="mt-2" :message="form.errors.email" />
62
+ </div>
63
+
64
+ <div class="flex items-center gap-4">
65
+ <PrimaryButton :disabled="form.processing">Save</PrimaryButton>
66
+
67
+ <Transition
68
+ enter-active-class="transition ease-in-out"
69
+ enter-from-class="opacity-0"
70
+ leave-active-class="transition ease-in-out"
71
+ leave-to-class="opacity-0"
72
+ >
73
+ <p v-if="form.recentlySuccessful" class="text-sm text-gray-600 dark:text-gray-400">Saved.</p>
74
+ </Transition>
75
+ </div>
76
+ </form>
77
+ </section>
78
+ </template>
@@ -0,0 +1,56 @@
1
+ <script setup lang="ts">
2
+ import { Head, Link } from '@inertiajs/vue3';
3
+ import { dashboard_path, login_path, register_path } from '@/routes';
4
+
5
+ defineProps<{
6
+ railsVersion: string;
7
+ rubyVersion: string;
8
+ }>();
9
+ </script>
10
+
11
+ <template>
12
+ <Head title="Welcome" />
13
+ <div
14
+ class="flex flex-col items-center justify-center bg-[#F0E7E9] bg-center bg-cover text-[#261B23] not-italic font-normal leading-tight min-h-screen text-center"
15
+ style="background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEwMjQiIHZpZXdCb3g9IjAgMCAxNDQwIDEwMjQiIHdpZHRoPSIxNDQwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0xNDQwIDUxMC4wMDA2NDh2LTUxMC4wMDA2NDhoLTE0NDB2Mzg0LjAwMDY0OGM0MTcuMzExOTM5IDEzMS4xNDIxNzkgODkxIDE3MS41MTMgMTQ0MCAxMjZ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);font-family: Sans-Serif;font-size: calc(0.9em + 0.5vw);"
16
+ >
17
+ <header class="absolute top-0 right-0 grid grid-cols-2 items-center gap-2 py-10 lg:grid-cols-3">
18
+ <div class="-mx-3 flex flex-1 justify-end">
19
+ <Link
20
+ href="dashboard_path()"
21
+ class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
22
+ v-if="$page.props.auth.user"
23
+ >
24
+ Dashboard
25
+ </Link>
26
+ <template v-else>
27
+ <Link
28
+ :href="login_path()"
29
+ class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
30
+ >
31
+ Log in
32
+ </Link>
33
+ <Link
34
+ :href="register_path()"
35
+ class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
36
+ >
37
+ Register
38
+ </Link>
39
+ </template>
40
+ </div>
41
+ </header>
42
+ <nav style="font-size: 0;height: 20vw;line-height: 0;max-height: 280px;max-width: 280px;min-height: 86px;min-width: 86px;width: 20vw;">
43
+ <a
44
+ class="bg-[#D30001] hover:bg-[#261B23] flex rounded-full" href="https://rubyonrails.org" target="_blank"
45
+ style="transition: background 0.25s cubic-bezier(0.33, 1, 0.68, 1);filter: drop-shadow(0 20px 13px rgb(0 0 0 / 0.03)) drop-shadow(0 8px 5px rgb(0 0 0 / 0.08));"
46
+ >
47
+ <img class="h-auto max-w-full w-full cursor-pointer" alt="" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjExMiIgdmlld0JveD0iMCAwIDExMiAxMTIiIHdpZHRoPSIxMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0ibTEwMC4wODIzNTcgNDguOTk5NTQwM3Y0LjExMzUwMzRoLTcuMzAwMzM4OHYxLjg5ODU0aDMuNjg0MDcxN2MxLjk3MjUwOTEgMCA0LjA3MjUzNDEgMS40NjY0MzExIDQuMTk3OTk3MSAzLjk2NjUxMjRsLjAwNTkxMy4yMzczOTc3djEuNTgyMTE2N2MtLjA4NzgyNCAzLjAwNzk1OS0yLjU0MzEyMTEgNC4xMzkwMDE4LTQuMDcxNTM4OSA0LjIwMTE3NzNsLS4xMzIzNzEyLjAwMjczMjhoLTcuMzkwNzQ1MXYtNC4wOTA5MDE4bDcuNDgxMTUxOC0uMDIyNjAxNnYtMS45ODg5NDY3aC0zLjQ4MDY1NjdjLTEuNzc1MjU4MyAwLTQuMDgxODMyMS0xLjMzODkxNTMtNC4yMTk5OTQyLTMuOTU0OTIwMWwtLjAwNjUxNzYtLjI0ODk5di0xLjQyMzkwNWMwLTIuNjk4MjQwMiAyLjI3ODIxMjktNC4xODI4NTMgNC4wNjU0NjQtNC4yNjc4NDkxbC4xNjEwNDc4LS4wMDM4NjZ6bS0xOC42OTE1NzkgMHYxMS44NjU4NzUyaDYuMTcwMjU1MXY0LjEzNjEwNTFoLTEwLjczNTc5MTl2LTE2LjAwMTk4MDN6bS02LjQ0MTQ3NTEgMHYxNi4wMDE5ODAzaC00LjU4ODEzODV2LTE2LjAwMTk4MDN6bS0xNS4yMTA5MjIgMGg0LjQwNzMyNTFsLjE4NzcyNC4wMDY2ODEyYy4wMzM4NjA5LjAwMjI3MzUuMDY4OTQ1Ny4wMDUxNDk5LjEwNTE2MDEuMDA4NjY0M2wuMjMwMDg3NS4wMjkwMTc4YzEuMjkxMzgyOS4xOTg1NDc2IDMuNTQ2MzgxNiAxLjEyMTM4MTYgMy42NzUxNzA4IDMuOTA2ODU4N2wuMDA1NzY3Ny4yNTI2ODgxdjExLjc5ODA3MDJoLTQuMjcxNzE1MXYtMi44MjUyMDg0aC00LjEzNjEwNTF2Mi44MjUyMDg0aC00LjQwNzMyNTF2LTExLjc5ODA3MDJjMC0xLjMxODQzMDYgMS4wMDQwODI2LTQuMDQ2ODQ5NSAzLjk0Njg5OS00LjE5NzQxMXptLTE5LjczOTg1MTktLjAwMjc1ODEgOC41ODAxODU3LjAwMDU3NDkuMjM4OTIzNC4wMzY3NDYyLjE0Nzk0NTkuMDI5NDE3LjI3NDExNjEuMDY1MzU4Mi4yMTI1MTk4LjA1OTkwNjguMjMyMzIyNS4wNzQ3MTgyYy4wNDAxNzkzLjAxMzc3MDQuMDgxMDQwMi4wMjgyMjAxLjEyMjUxMS4wNDMzODA0bC4yNTU1NjkxLjA5OTczNzYuMjY2NzYxOC4xMTgyODUyYzEuMzU2MDUxNS42NDAyODY2IDMuMDAyNjg1NSAyLjAzMjE1ODMgMy4wMDI2ODU1IDUuMDE2Mjk0IDAgMy4xODMwNzgxLTEuNTQ2NTI0MSA0LjUwMTQ4OTktMi42OTg4MzYyIDUuMDQyMDQ3N2wtLjIxMDk2NTEuMDkyNTA0NS0uMTk4ODgyOC4wNzU4NjU1LS4xODM5NTc3LjA2MDgxODYtLjE2NjE4OTguMDQ3MzYzNi0uMjA5NzUwOC4wNDkzMDAxLS4yNTk2NDkzLjA0MTgzNjMgNS4wMDU2ODk1IDUuMDUwNTgzNmgtNi4zNzQ5NTg5bC0zLjcyNjIwODMtMy44NjA4OTA2djMuODYwODkwNmgtNC4zMDk4MzE0em0yMi4wMDcwNjAzLTMuMDg2OTE5My40NDQ5OTE3LjQyMjY4MDctLjI0Mjk2OC4xNzc5ODgxLS4zNDgyMzMxLjI2OTMzNjUtLjE5OTg1NzMuMTYyOTIwNGMtNS4yMzk4OTY3LTMuODc0NTcxNS05LjY0NzY0NTQtNS40MjIxNDA5LTEzLjE5NzExOS01LjgxNTM1MzdsLS41MjU5ODA3LS4wNTA0NzA4Yy0xLjAzOTA3NDItLjA4NDIxMjYtMi4wMDA3ODYxLS4wNjk4MTAxLTIuODg0NDMwMi4wMTE1NDYybC0uNDM1MzEzMi4wNDYxMTExYy0uMDcxNDY2OC4wMDg1NjYyLS4xNDIzOTA3LjAxNzU2MDgtLjIxMjc3MTIuMDI2OTY1M2wtLjQxNTc1OTUuMDYxMjAwNS0uNDAyNjk5MS4wNzAxNjA3LS4zODk2MTk0LjA3ODI0MTUtLjM3NjUxOTguMDg1NDQyN2MtLjA2MTY2MDYuMDE0NzkxNy0uMTIyNzc0Ni4wMjk4NDY4LS4xODMzNDE1LjA0NTE0N2wtLjM1NjgzMzkuMDk0NTk1Ny0uMzQzNjg1NC4wOTk1OTgyLS4zMzA1MTc0LjEwMzcyMTMtLjMxNzMyOTcuMTA2OTY0OS0uMzA0MTIyNS4xMDkzMjktLjI5MDg5NTYuMTEwODEzNy0uNDExNTAwMi4xNjcwODAzLS41MDIxOTAyLjIxOTc2MTUtLjY1MzM3MzYuMzA4ODk1Ni0uNjEwMTA1LjMwMDU2NzVjLTQuNjk4ODg2NiAyLjYyMTk3ODgtNi44NTM5Mjk0IDYuODQ2MDcxMS03Ljc2ODIwMDIgMTAuODg2NjQ2M2wtLjEyMjMxMDEuNTc1NzgzOGMtLjAzODA1MDQuMTkxMzgzMy0uMDczNDI3OC4zODIxNTc2LS4xMDYyNzMyLjU3MjEzMDFsLS4wOTEwODA0LjU2NzMxOTYtLjA3NjczMTguNTYxMzUyMS0uMDYzMjI3NS41NTQyMjc3Yy0uMDA5NDU5NC4wOTE3MTM0LS4wMTgzOTE0LjE4MzA4MTctLjAyNjgxMzQuMjc0MDgwOGwtLjA0NDU1NC41NDEzNzIyLS4wMzMxNjAxLjUzMTM1NTZjLS4wMDQ2MjQyLjA4NzY2MDMtLjAwODgwODcuMTc0ODU1MS0uMDEyNTcxMy4yNjE1NjAybC0uMDE3NjUyNS41MTQxNjE4LS4wMDgzNjkzLjUwMTI1MzEuMDAwMDY5Ni40ODcxODc2LjAxNDA4MDYuNzAxODc3OS4wMjgzMTk1LjY2MzcyMjkuMDM5NzA4OS42MjE2NjM3LjA0ODI0OTIuNTc1Njk5OS4wNTM5NDAyLjUyNTgzMTcuMDc1ODQ4MS42MTY3ODc5LjA3NDE0NjIuNTExOTM3LjA4MDAwMDIuNDc4Mzc1Ni4wNjg1OTk1LjM1NDA4NjNoLTE3Ljg1NTMxN2wuMDU4NDktLjQ0MTcyNTMuMDQ2MzM2OC0uMjk1MTQ0OC4wNjMwMjA2LS4zNjQ3MjQyLjExMzI4MTktLjU4OTIwNjkuMTA5Mzc4Ny0uNTE1MDkwNy4xODIwMjY1LS43Nzg1MDg4LjE2NjEzNzYtLjY0ODY3NzIuMTI1OTIzMy0uNDYxNTk0My4yMTMwNDc0LS43MzM4MjI1LjE1ODk2NTUtLjUxNTUwNDIuMTczMTcyOC0uNTM1NDY5OS4xODc5NDYzLS41NTQ1MjI2LjIwMzI4NTctLjU3MjY2Mi4yMTkxOTEzLS41ODk4ODgzLjIzNTY2MjgtLjYwNjIwMTQuMjUyNzAwNC0uNjIxNjAxMmMuMDQzNTY4LS4xMDQ4MzI4LjA4Nzg2OTQtLjIxMDI2OTEuMTMyOTE2Mi0uMzE2MjkwMWwuMjc5MzE4LS42NDI5ODg3LjI5Nzc3MDctLjY1NjEwNTYuMzE2Nzg5NC0uNjY4MzA5Mi4zMzYzNzQtLjY3OTU5OTcuMzU2NTI0OS0uNjg5OTc3Yy4zNjY3ODg5LS42OTQ4NjExLjc2NDY1MjktMS40MDM5MTg0IDEuMTk2MTM5My0yLjEyMzA2MjQgNC43NDYzNTAxLTcuOTEwNTgzNCAxMi44Mzc3NDY5LTEzLjkwMDAyNTIgMTkuNDE0ODMyLTE0LjQ4NzY2ODYgNS4wNDUzODA2LS41MDU0MDk0IDkuODkyNTQzNi45Mjc2ODIzIDEzLjk0NDM2MjggMi44Nzk2NDM1bC42NDk5ODU4LjMyMDg1ODIuNjM1NDc2OC4zMjg2MDkzLjYyMDQwMTkuMzM1MDE1Yy4xMDIxMTI2LjA1NjI5NDkuMjAzNTczNi4xMTI4MDA3LjMwNDM3MS4xNjk0ODkybC41OTY3Mjg2LjM0MjEwMTMuNTgwMjM5LjM0NTE0MzkuNTYzMTgzNi4zNDY4NDExLjU0NTU2MjQuMzQ3MTkzMi41MjczNzUzLjM0NjE5OTkuNTA4NjIyMy4zNDM4NjE0Yy4wODMxNzYyLjA1NzA0MDYuMTY1NTQ3NS4xMTM5Mjc3LjI0NzEwMi4xNzA2MzMzbC40Nzk0MzIuMzM3ODMxMi40NTkyNjQ0LjMzMjEyOTQuNDM4NTMxLjMyNTA4MjUuNDE3MjMxNy4zMTY2OTAyLjU4NDY3MzYuNDU2MzU2OS41MzM1Njc0LjQyOTkwNzEuNjI4NjIzNy41MjQyMTc5LjY0NjM0MzIuNTYxNDAxNXptLTMwLjcwMDEwNTYgMTQuNTcxMzI0MyAyLjQ0MDk4MDEuODgxNDY1Yy4xMTMwMDgzLjg4NTIzMTkuMjczMTAzNCAxLjcyMzM3NzEuNDQxMDQ2NCAyLjQ4ODI3NjFsLjEwMTM5MzYuNDQ5OTQwNi0yLjcxMjIwMDEtLjk3MTg3MTctLjAzMzgzNDctLjIxMjE2MTgtLjA2NjA0MjEtLjQ3NTU4NDMtLjA2MTE2MDEtLjU0MTIxOTVjLS4wNDgwMjg1LS40Nzc0NjAyLS4wODc1ODE0LTEuMDE5OTAwMy0uMTEwMTgzMS0xLjYxODg0NDR6bTMxLjUwNjcyMzktNy42NjE5NjUyaC0xLjUxNDMxMTdjLS45NDAwMjM4IDAtMS4yMzkxMjI0LjQwOTc3Mi0xLjMzNDI5MDEuNjcwNTM2bC0uMDI4MjI2Ni4wOTUwMzM5Yy0uMDAzMjM3LjAxNDA3My0uMDA1ODI2Ni4wMjcxNTI2LS4wMDc4OTgyLjAzOTA3MzJsLS4wMDgxNTczLjA3MTUyMzktLjAwMDEyOTUgMy45MTUzODY0aDQuMTM2MTA1MWwtLjAwMTg1MzMtMy45MzQ3Njk0LS4wMTAyNjEyLS4wNjY5OTEzLS4wMjU3MjA3LS4wOTg3MjQxYy0uMDgzNTM1Ny0uMjU5MTUwNy0uMzUwOTEzNS0uNjkxMDY4Ni0xLjIwNTI1NjUtLjY5MTA2ODZ6bS01MC40OTIxMjQyLjMzOTAyNSAyLjU5OTE5MTcuOTQ5MjctLjQwODY0MS45NTE1ODM5Yy0uMjEyNDg4Mi40OTk0NjQ0LS40Mjc3Nzk2IDEuMDE0ODE0Mi0uNjAzMzU3NSAxLjQ1Nzc0NWwtLjExODA4NDkuMzAyODcxMi0yLjU5OTE5MTctLjk0OTI3LjEzMjM2NjItLjM0NTMwMzMuMjU4Mzg4OS0uNjM5MjAzNC4zMDU3MTExLS43MjgxOTc0LjMyNTQ4NzUtLjc1MzYyNDRjLjAzNjI0MzgtLjA4Mjc5NDMuMDcyMzQzNy0uMTY0ODgyMy4xMDgxMjk3LS4yNDU4NzE2em0zNS40NDUxMjA5LS4xNDM0NDQ5aC0zLjQ1Njg0Mzl2My42NTg4NjczaDMuNDM0Mzk2OGwuMDU0NzEwNi0uMDI1MzkyLjA4NjU5ODQtLjA0ODg5ODMuMTE0NzUzNi0uMDc4NjgyMmMuMjkyNjQyOC0uMjIxMTQ0OC43MzE2MDcxLS43MTQ5Nzk3LjczMTYwNzEtMS42ODc2ODQ3cy0uNDI4OTg3OC0xLjQ1NjU2MzQtLjcxNDk3OTctMS42NzEwNTczbC0uMTEyMTQ1NS0uMDc2MDc0MS0uMDg0NjMwMy0uMDQ2OTMwMXptLTE1LjQ0MjY0NTYtLjc2MDYyMTggMS42MjczMjAxIDEuMjg4Mjk1MWMtLjE4MDgxMzQuNzA1MTcyLS4zMTgyMzE1IDEuNDEwMzQ0LS40MTIyNTQ1IDIuMTE1NTE2bC0uMDYyMzgwNi41Mjg4NzktMS44MzA3MzUtMS40NDY1MDY3Yy4xODA4MTM0LS44MTM2Ni4zODQyMjg0LTEuNjQ5OTIxNy42NzgwNS0yLjQ4NjE4MzR6bTQuMDAwNDk1MS02LjMwNTg2NTEgMS4wMTcwNzUgMS41MzY5MTM0Yy0uMzk3Nzg5My40MTU4NzA3LS43NjY2NDg1LjgzMTc0MTMtMS4wOTUwMDU1IDEuMjcwNzU2MWwtLjIzODQ5MjguMzMzOTYyMy0xLjA4NDg4MDEtMS42MjczMjAxYy40MDY4My0uNTE5ODM4My44ODE0NjUxLTEuMDM5Njc2NyAxLjQwMTMwMzQtMS41MTQzMTE3em0tMTYuMTgyNzkzNi0zLjM0NTA0NjcgMS42MDQ3MTgzIDEuNDAxMzAzNGMtLjQwNjgzLjQyMzc4MTItLjgwMDk0NjUuODcyOTg5NC0xLjE3MjgxNDYgMS4zMjg1NTQybC0uMzY0MDk4Ny40NTY5Nzc1LTEuNzQwMzI4NC0xLjQ5MTcxMDFjLjUxOTgzODMtLjU2NTA0MTYgMS4wODQ4OC0xLjEzMDA4MzMgMS42NzI1MjM0LTEuNjk1MTI1em0yMi4zOTgyNTIxLS4wOTA0MDY3LjQ5NzIzNjYgMS40OTE3MTAxYy0uNTI0MzU4Ni4xNjI3MzItMS4wNDg3MTczLjM2ODg1OTItMS41NzMwNzYuNjA2ODA5NWwtLjM5MzI2OS4xODQyNDg4LS41MTk4Mzg0LTEuNTU5NTE1Yy41NjUwNDE3LS4yNDg2MTg0IDEuMjIwNDkwMS0uNDk3MjM2NyAxLjk4ODk0NjgtLjcyMzI1MzR6bTUuMjg4NzktLjU0MjQ0Yy41Nzg2MDI3LjAzNjE2MjcgMS4xNzE2NzA1LjEwMTI1NTUgMS43NzkyMDMzLjIwNjg1MDVsLjQ1ODM2MTguMDg2OTcxMi0uMDkwNDA2NyAxLjQwMTMwMzRjLS41OTY2ODQtLjEyNjU2OTQtMS4xOTMzNjgtLjIwOTc0MzUtMS43OTAwNTItLjI0OTUyMjRsLS40NDc1MTMtLjAyMTY5NzZ6bS0xOC41NTU5Njg2LTYuMjM4MDYwMSAxLjAxNzA3NSAxLjU1OTUxNWMtLjQ0MDczMjUuMjIwMzY2My0uODY4NzUxNi40NjYxNTk0LTEuMzAzMTI3NC43Mjc4NDQzbC0uNDM3MjAxLjI2NjYyOTEtMS4wMzk2NzY3LTEuNTgyMTE2N2MuNjEwMjQ1LS4zNjE2MjY3IDEuMTk3ODg4NC0uNjc4MDUgMS43NjI5MzAxLS45NzE4NzE3em0xOC41MTA3NjUzLjYzMjg0NjcuMDkwNDA2Ny0xLjQ5MTcxLjQ0MzUwNzMuMTMwNTU2NC4zODM5ODAzLjEyMDMyNTIuMzI4NTQ1OC4xMDk5MDc5LjI3NzIwMzcuMDk5MzA0OC4zMjg0OTE1LjEyODY2OS4yOTY0ODguMTMyNzExMi4xMzQxNDUxLjA2OTU4MzgtLjA5MDQwNjcgMS41MTQzMTE3Yy0uNDgyMTY4OS0uMTk1ODgxMS0uOTY0MzM3OC0uMzgxNzE3LTEuNDUzMjAzNS0uNTU3NTA3OHptLTguNTQzNDMwMS0yLjgyNTIwODQuNDUyMDMzMyAxLjM3ODcwMTdoLS4yMjYwMTY3Yy0uNDkxNTg2MiAwLS45ODMxNzI1LjAxMjcxMzQtMS40NzQ3NTg4LjA0NzY3NTRsLS40OTE1ODYyLjA0MjczMTMtLjQyOTQzMTctMS4zMzM0OTg0Yy43NDU4NTUtLjA5MDQwNjcgMS40NjkxMDg0LS4xMzU2MSAyLjE2OTc2MDEtLjEzNTYxeiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==" />
48
+ </a>
49
+ </nav>
50
+
51
+ <ul class="bottom-0 left-0 list-none mx-8 mt-0 mb-8 right-0 absolute">
52
+ <li><strong>Rails version:</strong> {{ railsVersion }}</li>
53
+ <li><strong>Ruby version:</strong> {{ rubyVersion }}</li>
54
+ </ul>
55
+ </div>
56
+ </template>
@@ -0,0 +1,34 @@
1
+ import './bootstrap'
2
+ import '../../assets/builds/tailwind.css'
3
+
4
+ import { createApp, h, DefineComponent } from 'vue';
5
+ import { createInertiaApp } from '@inertiajs/vue3';
6
+
7
+ async function resolvePageComponent<T>(path: string|string[], pages: Record<string, Promise<T> | (() => Promise<T>)>): Promise<T> {
8
+ for (const p of (Array.isArray(path) ? path : [path])) {
9
+ const page = pages[p]
10
+
11
+ if (typeof page === 'undefined') {
12
+ continue
13
+ }
14
+
15
+ return typeof page === 'function' ? page() : page
16
+ }
17
+
18
+ throw new Error(`Page not found: ${path}`)
19
+ }
20
+
21
+ const appName = import.meta.env.VITE_APP_NAME || 'Rails';
22
+
23
+ createInertiaApp({
24
+ title: (title) => `${title} - ${appName}`,
25
+ resolve: (name) => resolvePageComponent(`../Pages/${name}.vue`, import.meta.glob<DefineComponent>('../Pages/**/*.vue')),
26
+ setup({ el, App, props, plugin }) {
27
+ createApp({ render: () => h(App, props) })
28
+ .use(plugin)
29
+ .mount(el);
30
+ },
31
+ progress: {
32
+ color: '#4B5563',
33
+ },
34
+ });
@@ -0,0 +1,4 @@
1
+ import axios from 'axios';
2
+ window.axios = axios;
3
+
4
+ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
@@ -0,0 +1,13 @@
1
+ import { PageProps as InertiaPageProps } from '@inertiajs/core';
2
+ import { AxiosInstance } from 'axios';
3
+ import { PageProps as AppPageProps } from './';
4
+
5
+ declare global {
6
+ interface Window {
7
+ axios: AxiosInstance;
8
+ }
9
+ }
10
+
11
+ declare module '@inertiajs/core' {
12
+ interface PageProps extends InertiaPageProps, AppPageProps {}
13
+ }
@@ -0,0 +1,12 @@
1
+ export interface User {
2
+ id: number;
3
+ name: string;
4
+ email: string;
5
+ email_verified_at: string;
6
+ }
7
+
8
+ export type PageProps<T extends Record<string, unknown> = Record<string, unknown>> = T & {
9
+ auth: {
10
+ user: User;
11
+ };
12
+ };
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+
7
+ <title><%= content_for(:title) || "Rails" %></title>
8
+
9
+ <%= csrf_meta_tags %>
10
+ <%= csp_meta_tag %>
11
+
12
+ <!-- Fonts -->
13
+ <link rel="preconnect" href="https://fonts.bunny.net">
14
+ <link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
15
+
16
+ <%= vite_client_tag %>
17
+ <%= vite_typescript_tag 'application.ts', defer: true %>
18
+ </head>
19
+
20
+ <body class="font-sans antialiased">
21
+ <div class="min-h-screen bg-gray-100">
22
+ <%= yield %>
23
+ </div>
24
+ </body>
25
+ </html>
@@ -0,0 +1,22 @@
1
+ import defaultTheme from 'tailwindcss/defaultTheme';
2
+ import forms from '@tailwindcss/forms';
3
+
4
+ /** @type {import('tailwindcss').Config} */
5
+ export default {
6
+ content: [
7
+ './public/*.html',
8
+ './app/helpers/**/*.rb',
9
+ './app/views/**/*',
10
+ './app/javascript/**/*.vue',
11
+ ],
12
+
13
+ theme: {
14
+ extend: {
15
+ fontFamily: {
16
+ sans: ['Figtree', ...defaultTheme.fontFamily.sans],
17
+ },
18
+ },
19
+ },
20
+
21
+ plugins: [forms],
22
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "scripts": {
5
+ "dev": "vite",
6
+ "build": "tsc && bin/rails tailwindcss:build && vite build"
7
+ },
8
+ "devDependencies": {
9
+ "@headlessui/vue": "^1.7.22",
10
+ "@inertiajs/vue3": "^1.1.0",
11
+ "@tailwindcss/forms": "^0.5.7",
12
+ "@types/node": "^18.13.0",
13
+ "@vitejs/plugin-vue": "^5.0.5",
14
+ "autoprefixer": "^10.4.12",
15
+ "axios": "^1.6.4",
16
+ "postcss": "^8.4.31",
17
+ "tailwindcss": "^3.2.1",
18
+ "typescript": "^5.0.2",
19
+ "vite": "^5.2.11",
20
+ "vite-plugin-rails": "^0.5.0",
21
+ "vue": "^3.4.27",
22
+ "vue-tsc": "^2.0.21"
23
+ }
24
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "preserve",
7
+ "strict": true,
8
+ "isolatedModules": true,
9
+ "target": "ESNext",
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "noEmit": true,
13
+ "skipLibCheck": true,
14
+ "paths": {
15
+ "@/*": ["./app/javascript/*"]
16
+ }
17
+ },
18
+ "include": ["app/javascript/**/*.ts", "app/javascript/**/*.d.ts", "app/javascript/**/*.vue"]
19
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vite'
2
+ import Rails from 'vite-plugin-rails'
3
+ import vue from '@vitejs/plugin-vue'
4
+
5
+ export default defineConfig({
6
+ resolve: {
7
+ dedupe: ['axios']
8
+ },
9
+ plugins: [
10
+ Rails(),
11
+ vue(),
12
+ ],
13
+ })