kaze 1.4.0 → 2.0.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 (262) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -1
  3. data/README.md +1 -1
  4. data/lib/kaze/commands/app/base_stack.rb +12 -2
  5. data/lib/kaze/commands/app/hotwire_stack.rb +3 -1
  6. data/lib/kaze/commands/app/inertia_react_stack.rb +6 -2
  7. data/lib/kaze/commands/app/inertia_vue_stack.rb +6 -2
  8. data/lib/kaze/commands/app.rb +9 -2
  9. data/lib/kaze/version.rb +1 -1
  10. data/stubs/default/config/routes.rb +11 -4
  11. data/stubs/default/test/integration/appearance_test.rb +11 -0
  12. data/stubs/default/test/integration/password_update_test.rb +9 -1
  13. data/stubs/hotwire/app/assets/tailwind/application.css +119 -1
  14. data/stubs/hotwire/app/components/breadcrumbs_component.rb +32 -0
  15. data/stubs/hotwire/app/components/danger_button_component.rb +1 -1
  16. data/stubs/hotwire/app/components/dropdown_component.html.erb +2 -2
  17. data/stubs/hotwire/app/components/dropdown_component.rb +5 -1
  18. data/stubs/hotwire/app/components/dropdown_link_component.rb +1 -1
  19. data/stubs/hotwire/app/components/heading_component.rb +19 -0
  20. data/stubs/hotwire/app/components/icon_component.rb +30 -0
  21. data/stubs/hotwire/app/components/input_error_component.rb +1 -1
  22. data/stubs/hotwire/app/components/input_label_component.rb +3 -3
  23. data/stubs/hotwire/app/components/modal_component.html.erb +2 -2
  24. data/stubs/hotwire/app/components/primary_button_component.rb +1 -1
  25. data/stubs/hotwire/app/components/secondary_button_component.rb +1 -1
  26. data/stubs/hotwire/app/components/sidebar_menu_button_component.rb +25 -0
  27. data/stubs/hotwire/app/components/text_input_component.rb +1 -1
  28. data/stubs/hotwire/app/components/user_avatar_component.rb +27 -0
  29. data/stubs/hotwire/app/controllers/application_controller.rb +1 -0
  30. data/stubs/hotwire/app/controllers/concerns/sidebar_state.rb +14 -0
  31. data/stubs/hotwire/app/controllers/settings/appearance_controller.rb +7 -0
  32. data/stubs/hotwire/app/controllers/settings/password_controller.rb +19 -0
  33. data/stubs/hotwire/app/controllers/{profile_controller.rb → settings/profile_controller.rb} +3 -4
  34. data/stubs/hotwire/app/views/auth/login.html.erb +1 -1
  35. data/stubs/hotwire/app/views/dashboard/index.html.erb +6 -11
  36. data/stubs/hotwire/app/views/layouts/_settings.html.erb +26 -0
  37. data/stubs/hotwire/app/views/layouts/_sidebar.html.erb +56 -0
  38. data/stubs/hotwire/app/views/layouts/_sidebar_header.html.erb +11 -0
  39. data/stubs/hotwire/app/views/layouts/_sidebar_user.html.erb +34 -0
  40. data/stubs/hotwire/app/views/layouts/application.html.erb +24 -15
  41. data/stubs/hotwire/app/views/settings/appearance/_update_appearance_form.html.erb +28 -0
  42. data/stubs/hotwire/app/views/settings/appearance/edit.html.erb +10 -0
  43. data/stubs/hotwire/app/views/{profile/partials → settings/password}/_update_password_form.html.erb +2 -10
  44. data/stubs/hotwire/app/views/settings/password/edit.html.erb +10 -0
  45. data/stubs/hotwire/app/views/{profile/partials → settings/profile}/_confirm_user_deletion_modal.html.erb +2 -2
  46. data/stubs/hotwire/app/views/settings/profile/_delete_user_form.html.erb +6 -0
  47. data/stubs/hotwire/app/views/{profile/partials → settings/profile}/_update_profile_information_form.html.erb +4 -12
  48. data/stubs/hotwire/app/views/{profile → settings/profile}/destroy.turbo_stream.erb +1 -1
  49. data/stubs/hotwire/app/views/settings/profile/edit.html.erb +14 -0
  50. data/stubs/inertia-common/app/controllers/concerns/handle_inertia_requests.rb +4 -1
  51. data/stubs/inertia-common/app/controllers/settings/appearance_controller.rb +7 -0
  52. data/stubs/inertia-common/app/controllers/settings/password_controller.rb +17 -0
  53. data/stubs/inertia-common/app/controllers/{profile_controller.rb → settings/profile_controller.rb} +2 -2
  54. data/stubs/inertia-common/test/integration/appearance_test.rb +11 -0
  55. data/stubs/inertia-common/test/integration/password_update_test.rb +10 -2
  56. data/stubs/inertia-react-ts/app/assets/tailwind/application.css +120 -1
  57. data/stubs/inertia-react-ts/app/javascript/Components/AppLogo.tsx +17 -0
  58. data/stubs/inertia-react-ts/app/javascript/Components/AppShell.tsx +9 -0
  59. data/stubs/inertia-react-ts/app/javascript/Components/AppSidebar.tsx +65 -0
  60. data/stubs/inertia-react-ts/app/javascript/Components/AppSidebarHeader.tsx +14 -0
  61. data/stubs/inertia-react-ts/app/javascript/Components/Breadcrumbs.tsx +43 -0
  62. data/stubs/inertia-react-ts/app/javascript/Components/Heading.tsx +19 -0
  63. data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +1 -1
  64. data/stubs/inertia-react-ts/app/javascript/Components/NavFooter.tsx +32 -0
  65. data/stubs/inertia-react-ts/app/javascript/Components/NavMain.tsx +32 -0
  66. data/stubs/inertia-react-ts/app/javascript/Components/NavUser.tsx +39 -0
  67. data/stubs/inertia-react-ts/app/javascript/Components/UserInfo.tsx +23 -0
  68. data/stubs/inertia-react-ts/app/javascript/Components/UserMenuContent.tsx +57 -0
  69. data/stubs/inertia-react-ts/app/javascript/Components/ui/avatar.tsx +51 -0
  70. data/stubs/inertia-react-ts/app/javascript/Components/ui/breadcrumb.tsx +109 -0
  71. data/stubs/inertia-react-ts/app/javascript/Components/ui/button.tsx +49 -0
  72. data/stubs/inertia-react-ts/app/javascript/Components/ui/checkbox.tsx +27 -0
  73. data/stubs/inertia-react-ts/app/javascript/Components/ui/dialog.tsx +109 -0
  74. data/stubs/inertia-react-ts/app/javascript/Components/ui/dropdown-menu.tsx +217 -0
  75. data/stubs/inertia-react-ts/app/javascript/Components/ui/input.tsx +21 -0
  76. data/stubs/inertia-react-ts/app/javascript/Components/ui/label.tsx +19 -0
  77. data/stubs/inertia-react-ts/app/javascript/Components/ui/separator.tsx +26 -0
  78. data/stubs/inertia-react-ts/app/javascript/Components/ui/sheet.tsx +137 -0
  79. data/stubs/inertia-react-ts/app/javascript/Components/ui/sidebar.tsx +719 -0
  80. data/stubs/inertia-react-ts/app/javascript/Components/ui/skeleton.tsx +13 -0
  81. data/stubs/inertia-react-ts/app/javascript/Components/ui/tooltip.tsx +55 -0
  82. data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +19 -127
  83. data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +1 -1
  84. data/stubs/inertia-react-ts/app/javascript/Layouts/SettingsLayout.tsx +57 -0
  85. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +6 -6
  86. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +17 -12
  87. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +14 -14
  88. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +10 -10
  89. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/VerifyEmail.tsx +2 -2
  90. data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +13 -8
  91. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Appearance.tsx +33 -0
  92. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Partials/DeleteUserForm.tsx +107 -0
  93. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Partials/UpdateAppearanceForm.tsx +41 -0
  94. data/stubs/inertia-react-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdatePasswordForm.tsx +12 -20
  95. data/stubs/inertia-react-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdateProfileInformationForm.tsx +13 -21
  96. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Password.tsx +33 -0
  97. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Profile.tsx +35 -0
  98. data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +6 -1
  99. data/stubs/inertia-react-ts/app/javascript/hooks/use-initials.tsx +23 -0
  100. data/stubs/inertia-react-ts/app/javascript/hooks/use-mobile-navigation.tsx +11 -0
  101. data/stubs/inertia-react-ts/app/javascript/hooks/use-mobile.tsx +36 -0
  102. data/stubs/inertia-react-ts/app/javascript/lib/appearance.ts +1 -2
  103. data/stubs/inertia-react-ts/app/javascript/lib/utils.ts +6 -0
  104. data/stubs/inertia-react-ts/app/javascript/types/global.d.ts +2 -2
  105. data/stubs/inertia-react-ts/app/javascript/types/index.d.ts +14 -0
  106. data/stubs/inertia-react-ts/components.json +21 -0
  107. data/stubs/inertia-react-ts/package.json +13 -0
  108. data/stubs/inertia-vue-ts/app/assets/tailwind/application.css +120 -1
  109. data/stubs/inertia-vue-ts/app/javascript/Components/AppLogo.vue +17 -0
  110. data/stubs/inertia-vue-ts/app/javascript/Components/AppShell.vue +12 -0
  111. data/stubs/inertia-vue-ts/app/javascript/Components/AppSidebar.vue +65 -0
  112. data/stubs/inertia-vue-ts/app/javascript/Components/AppSidebarHeader.vue +20 -0
  113. data/stubs/inertia-vue-ts/app/javascript/Components/Breadcrumbs.vue +32 -0
  114. data/stubs/inertia-vue-ts/app/javascript/Components/Heading.vue +15 -0
  115. data/stubs/inertia-vue-ts/app/javascript/Components/InputError.vue +1 -1
  116. data/stubs/inertia-vue-ts/app/javascript/Components/NavFooter.vue +33 -0
  117. data/stubs/inertia-vue-ts/app/javascript/Components/NavMain.vue +32 -0
  118. data/stubs/inertia-vue-ts/app/javascript/Components/NavUser.vue +40 -0
  119. data/stubs/inertia-vue-ts/app/javascript/Components/UserInfo.vue +25 -0
  120. data/stubs/inertia-vue-ts/app/javascript/Components/UserMenuContent.vue +47 -0
  121. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/Avatar.vue +18 -0
  122. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/AvatarFallback.vue +21 -0
  123. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/AvatarImage.vue +16 -0
  124. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/index.ts +3 -0
  125. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/Breadcrumb.vue +17 -0
  126. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbEllipsis.vue +23 -0
  127. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
  128. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbLink.vue +21 -0
  129. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbList.vue +17 -0
  130. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
  131. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbSeparator.vue +22 -0
  132. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/index.ts +7 -0
  133. data/stubs/inertia-vue-ts/app/javascript/Components/ui/button/Button.vue +31 -0
  134. data/stubs/inertia-vue-ts/app/javascript/Components/ui/button/index.ts +34 -0
  135. data/stubs/inertia-vue-ts/app/javascript/Components/ui/checkbox/Checkbox.vue +35 -0
  136. data/stubs/inertia-vue-ts/app/javascript/Components/ui/checkbox/index.ts +1 -0
  137. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/Dialog.vue +15 -0
  138. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogClose.vue +12 -0
  139. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogContent.vue +52 -0
  140. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogDescription.vue +23 -0
  141. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogFooter.vue +25 -0
  142. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogHeader.vue +14 -0
  143. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogOverlay.vue +26 -0
  144. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogTitle.vue +23 -0
  145. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogTrigger.vue +12 -0
  146. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/index.ts +9 -0
  147. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenu.vue +15 -0
  148. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuContent.vue +37 -0
  149. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  150. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
  151. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -0
  152. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  153. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuTrigger.vue +14 -0
  154. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/index.ts +7 -0
  155. data/stubs/inertia-vue-ts/app/javascript/Components/ui/input/Input.vue +50 -0
  156. data/stubs/inertia-vue-ts/app/javascript/Components/ui/input/index.ts +1 -0
  157. data/stubs/inertia-vue-ts/app/javascript/Components/ui/label/Label.vue +26 -0
  158. data/stubs/inertia-vue-ts/app/javascript/Components/ui/label/index.ts +1 -0
  159. data/stubs/inertia-vue-ts/app/javascript/Components/ui/separator/Separator.vue +29 -0
  160. data/stubs/inertia-vue-ts/app/javascript/Components/ui/separator/index.ts +1 -0
  161. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/Sheet.vue +19 -0
  162. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetClose.vue +15 -0
  163. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetContent.vue +62 -0
  164. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetDescription.vue +21 -0
  165. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetFooter.vue +16 -0
  166. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetHeader.vue +15 -0
  167. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetOverlay.vue +21 -0
  168. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetTitle.vue +21 -0
  169. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetTrigger.vue +15 -0
  170. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/index.ts +8 -0
  171. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/Sidebar.vue +96 -0
  172. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarContent.vue +18 -0
  173. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarFooter.vue +18 -0
  174. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroup.vue +18 -0
  175. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroupAction.vue +27 -0
  176. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroupContent.vue +18 -0
  177. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroupLabel.vue +25 -0
  178. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarHeader.vue +18 -0
  179. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarInput.vue +22 -0
  180. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarInset.vue +21 -0
  181. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenu.vue +18 -0
  182. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuAction.vue +35 -0
  183. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuBadge.vue +26 -0
  184. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuButton.vue +48 -0
  185. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
  186. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuItem.vue +18 -0
  187. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
  188. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSub.vue +22 -0
  189. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSubButton.vue +36 -0
  190. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
  191. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarProvider.vue +82 -0
  192. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarRail.vue +33 -0
  193. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarSeparator.vue +19 -0
  194. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarTrigger.vue +28 -0
  195. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/index.ts +60 -0
  196. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/utils.ts +19 -0
  197. data/stubs/inertia-vue-ts/app/javascript/Components/ui/skeleton/Skeleton.vue +17 -0
  198. data/stubs/inertia-vue-ts/app/javascript/Components/ui/skeleton/index.ts +1 -0
  199. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/Tooltip.vue +19 -0
  200. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/TooltipContent.vue +34 -0
  201. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/TooltipProvider.vue +14 -0
  202. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/TooltipTrigger.vue +15 -0
  203. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/index.ts +4 -0
  204. data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +17 -147
  205. data/stubs/inertia-vue-ts/app/javascript/Layouts/SettingsLayout.vue +57 -0
  206. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +7 -7
  207. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +10 -12
  208. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +12 -14
  209. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +8 -10
  210. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/VerifyEmail.vue +3 -3
  211. data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +15 -10
  212. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Appearance.vue +33 -0
  213. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Partials/DeleteUserForm.vue +96 -0
  214. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Partials/UpdateAppearanceForm.vue +42 -0
  215. data/stubs/inertia-vue-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdatePasswordForm.vue +12 -20
  216. data/stubs/inertia-vue-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdateProfileInformationForm.vue +12 -20
  217. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Password.vue +33 -0
  218. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Profile.vue +40 -0
  219. data/stubs/inertia-vue-ts/app/javascript/composables/useInitials.ts +29 -0
  220. data/stubs/inertia-vue-ts/app/javascript/lib/appearance.ts +1 -2
  221. data/stubs/inertia-vue-ts/app/javascript/lib/utils.ts +6 -0
  222. data/stubs/inertia-vue-ts/app/javascript/types/index.d.ts +14 -0
  223. data/stubs/inertia-vue-ts/app/javascript/types/vue-shims.d.ts +10 -0
  224. data/stubs/inertia-vue-ts/components.json +20 -0
  225. data/stubs/inertia-vue-ts/package.json +8 -1
  226. data/stubs/inertia-vue-ts/vite.config.ts +25 -1
  227. metadata +171 -46
  228. data/stubs/hotwire/app/components/nav_link_component.rb +0 -15
  229. data/stubs/hotwire/app/components/responsive_nav_link_component.rb +0 -15
  230. data/stubs/hotwire/app/controllers/password_controller.rb +0 -13
  231. data/stubs/hotwire/app/views/layouts/_navigation.html.erb +0 -82
  232. data/stubs/hotwire/app/views/profile/edit.html.erb +0 -29
  233. data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +0 -14
  234. data/stubs/hotwire/app/views/profile/partials/_update_appearance_form.html.erb +0 -39
  235. data/stubs/inertia-common/app/controllers/password_controller.rb +0 -13
  236. data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +0 -11
  237. data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +0 -20
  238. data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +0 -100
  239. data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +0 -14
  240. data/stubs/inertia-react-ts/app/javascript/Components/Modal.tsx +0 -66
  241. data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +0 -21
  242. data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +0 -20
  243. data/stubs/inertia-react-ts/app/javascript/Components/ResponsiveNavLink.tsx +0 -21
  244. data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +0 -22
  245. data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +0 -32
  246. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +0 -37
  247. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +0 -102
  248. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/UpdateAppearanceForm.tsx +0 -47
  249. data/stubs/inertia-vue-ts/app/javascript/Components/Checkbox.vue +0 -29
  250. data/stubs/inertia-vue-ts/app/javascript/Components/DangerButton.vue +0 -7
  251. data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +0 -75
  252. data/stubs/inertia-vue-ts/app/javascript/Components/DropdownLink.vue +0 -16
  253. data/stubs/inertia-vue-ts/app/javascript/Components/InputLabel.vue +0 -12
  254. data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +0 -109
  255. data/stubs/inertia-vue-ts/app/javascript/Components/NavLink.vue +0 -21
  256. data/stubs/inertia-vue-ts/app/javascript/Components/PrimaryButton.vue +0 -7
  257. data/stubs/inertia-vue-ts/app/javascript/Components/ResponsiveNavLink.vue +0 -21
  258. data/stubs/inertia-vue-ts/app/javascript/Components/SecondaryButton.vue +0 -19
  259. data/stubs/inertia-vue-ts/app/javascript/Components/TextInput.vue +0 -23
  260. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +0 -43
  261. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +0 -99
  262. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/UpdateAppearanceForm.vue +0 -47
@@ -1,100 +0,0 @@
1
- import { useState, createContext, useContext, PropsWithChildren, Dispatch, SetStateAction } from 'react'
2
- import { Link, InertiaLinkProps } from '@inertiajs/react'
3
- import { Transition } from '@headlessui/react'
4
-
5
- const DropDownContext = createContext<{
6
- open: boolean
7
- setOpen: Dispatch<SetStateAction<boolean>>
8
- toggleOpen: () => void
9
- }>({
10
- open: false,
11
- setOpen: () => {},
12
- toggleOpen: () => {},
13
- })
14
-
15
- const Dropdown = ({ children }: PropsWithChildren) => {
16
- const [open, setOpen] = useState(false)
17
-
18
- const toggleOpen = () => {
19
- setOpen((previousState) => !previousState)
20
- }
21
-
22
- return (
23
- <DropDownContext.Provider value={{ open, setOpen, toggleOpen }}>
24
- <div className="relative">{children}</div>
25
- </DropDownContext.Provider>
26
- )
27
- }
28
-
29
- const Trigger = ({ children }: PropsWithChildren) => {
30
- const { open, setOpen, toggleOpen } = useContext(DropDownContext)
31
-
32
- return (
33
- <>
34
- <div onClick={toggleOpen}>{children}</div>
35
-
36
- {open && <div className="fixed inset-0 z-40" onClick={() => setOpen(false)}></div>}
37
- </>
38
- )
39
- }
40
-
41
- const Content = ({
42
- align = 'right',
43
- width = '48',
44
- contentClasses = 'py-1 bg-white dark:bg-gray-700',
45
- children,
46
- }: PropsWithChildren<{ align?: 'left' | 'right'; width?: '48'; contentClasses?: string }>) => {
47
- const { open, setOpen } = useContext(DropDownContext)
48
-
49
- let alignmentClasses = 'origin-top'
50
-
51
- if (align === 'left') {
52
- alignmentClasses = 'ltr:origin-top-left rtl:origin-top-right start-0'
53
- } else if (align === 'right') {
54
- alignmentClasses = 'ltr:origin-top-right rtl:origin-top-left end-0'
55
- }
56
-
57
- let widthClasses = ''
58
-
59
- if (width === '48') {
60
- widthClasses = 'w-48'
61
- }
62
-
63
- return (
64
- <>
65
- <Transition
66
- show={open}
67
- enter="transition ease-out duration-200"
68
- enterFrom="opacity-0 scale-95"
69
- enterTo="opacity-100 scale-100"
70
- leave="transition ease-in duration-75"
71
- leaveFrom="opacity-100 scale-100"
72
- leaveTo="opacity-0 scale-95"
73
- >
74
- <div
75
- className={`absolute z-50 mt-2 rounded-md shadow-lg ${alignmentClasses} ${widthClasses}`}
76
- onClick={() => setOpen(false)}
77
- >
78
- <div className={`rounded-md ring-1 ring-black ring-opacity-5 ${contentClasses}`}>{children}</div>
79
- </div>
80
- </Transition>
81
- </>
82
- )
83
- }
84
-
85
- const DropdownLink = ({ className = '', children, ...props }: InertiaLinkProps) => {
86
- return (
87
- <Link
88
- {...props}
89
- className={`block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out ${className}`}
90
- >
91
- {children}
92
- </Link>
93
- )
94
- }
95
-
96
- Dropdown.Trigger = Trigger
97
- Dropdown.Content = Content
98
- Dropdown.Link = DropdownLink
99
-
100
- export default Dropdown
@@ -1,14 +0,0 @@
1
- import { LabelHTMLAttributes } from 'react'
2
-
3
- export default function InputLabel({
4
- value,
5
- className = '',
6
- children,
7
- ...props
8
- }: LabelHTMLAttributes<HTMLLabelElement> & { value?: string }) {
9
- return (
10
- <label {...props} className={`block font-medium text-sm text-gray-700 dark:text-gray-300 ${className}`}>
11
- {value ? value : children}
12
- </label>
13
- )
14
- }
@@ -1,66 +0,0 @@
1
- import { PropsWithChildren } from 'react'
2
- import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
3
-
4
- export default function Modal({
5
- children,
6
- show = false,
7
- maxWidth = '2xl',
8
- closeable = true,
9
- onClose = () => {},
10
- }: PropsWithChildren<{
11
- show: boolean
12
- maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'
13
- closeable?: boolean
14
- onClose: CallableFunction
15
- }>) {
16
- const close = () => {
17
- if (closeable) {
18
- onClose()
19
- }
20
- }
21
-
22
- const maxWidthClass = {
23
- sm: 'sm:max-w-sm',
24
- md: 'sm:max-w-md',
25
- lg: 'sm:max-w-lg',
26
- xl: 'sm:max-w-xl',
27
- '2xl': 'sm:max-w-2xl',
28
- }[maxWidth]
29
-
30
- return (
31
- <Transition show={show} leave="duration-200">
32
- <Dialog
33
- as="div"
34
- id="modal"
35
- className="fixed inset-0 flex overflow-y-auto px-4 py-6 sm:px-0 items-center z-50 transform transition-all"
36
- onClose={close}
37
- >
38
- <TransitionChild
39
- enter="ease-out duration-300"
40
- enterFrom="opacity-0"
41
- enterTo="opacity-100"
42
- leave="ease-in duration-200"
43
- leaveFrom="opacity-100"
44
- leaveTo="opacity-0"
45
- >
46
- <div className="absolute inset-0 bg-gray-500/75 dark:bg-gray-900/75" />
47
- </TransitionChild>
48
-
49
- <TransitionChild
50
- enter="ease-out duration-300"
51
- enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
52
- enterTo="opacity-100 translate-y-0 sm:scale-100"
53
- leave="ease-in duration-200"
54
- leaveFrom="opacity-100 translate-y-0 sm:scale-100"
55
- leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
56
- >
57
- <DialogPanel
58
- className={`mb-6 bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto ${maxWidthClass}`}
59
- >
60
- {children}
61
- </DialogPanel>
62
- </TransitionChild>
63
- </Dialog>
64
- </Transition>
65
- )
66
- }
@@ -1,21 +0,0 @@
1
- import { Link, InertiaLinkProps } from '@inertiajs/react'
2
-
3
- export default function NavLink({
4
- active = false,
5
- className = '',
6
- children,
7
- ...props
8
- }: InertiaLinkProps & { active: boolean }) {
9
- return (
10
- <Link
11
- {...props}
12
- className={`inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium leading-5 transition duration-150 ease-in-out focus:outline-hidden ${
13
- active
14
- ? 'border-indigo-400 dark:border-indigo-600 text-gray-900 dark:text-gray-100 focus:border-indigo-700 '
15
- : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 '
16
- } ${className}`}
17
- >
18
- {children}
19
- </Link>
20
- )
21
- }
@@ -1,20 +0,0 @@
1
- import { ButtonHTMLAttributes } from 'react'
2
-
3
- export default function PrimaryButton({
4
- className = '',
5
- disabled,
6
- children,
7
- ...props
8
- }: ButtonHTMLAttributes<HTMLButtonElement>) {
9
- return (
10
- <button
11
- {...props}
12
- className={`inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150 ${
13
- disabled && 'opacity-25'
14
- } ${className}`}
15
- disabled={disabled}
16
- >
17
- {children}
18
- </button>
19
- )
20
- }
@@ -1,21 +0,0 @@
1
- import { Link, InertiaLinkProps } from '@inertiajs/react'
2
-
3
- export default function ResponsiveNavLink({
4
- active = false,
5
- className = '',
6
- children,
7
- ...props
8
- }: InertiaLinkProps & { active?: boolean }) {
9
- return (
10
- <Link
11
- {...props}
12
- className={`w-full flex items-start ps-3 pe-4 py-2 border-l-4 ${
13
- active
14
- ? 'border-indigo-400 dark:border-indigo-600 text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300'
15
- : 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:text-gray-800 dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600'
16
- } text-base font-medium focus:outline-hidden transition duration-150 ease-in-out ${className}`}
17
- >
18
- {children}
19
- </Link>
20
- )
21
- }
@@ -1,22 +0,0 @@
1
- import { ButtonHTMLAttributes } from 'react'
2
-
3
- export default function SecondaryButton({
4
- type = 'button',
5
- className = '',
6
- disabled,
7
- children,
8
- ...props
9
- }: ButtonHTMLAttributes<HTMLButtonElement>) {
10
- return (
11
- <button
12
- {...props}
13
- type={type}
14
- className={`inline-flex items-center px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-xs hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150 ${
15
- disabled && 'opacity-25'
16
- } ${className}`}
17
- disabled={disabled}
18
- >
19
- {children}
20
- </button>
21
- )
22
- }
@@ -1,32 +0,0 @@
1
- import { forwardRef, useEffect, useImperativeHandle, useRef, InputHTMLAttributes } from 'react'
2
-
3
- export default forwardRef(function TextInput(
4
- {
5
- type = 'text',
6
- className = '',
7
- isFocused = false,
8
- ...props
9
- }: InputHTMLAttributes<HTMLInputElement> & { isFocused?: boolean },
10
- ref,
11
- ) {
12
- const localRef = useRef<HTMLInputElement>(null)
13
-
14
- useImperativeHandle(ref, () => ({
15
- focus: () => localRef.current?.focus(),
16
- }))
17
-
18
- useEffect(() => {
19
- if (isFocused) {
20
- localRef.current?.focus()
21
- }
22
- }, [])
23
-
24
- return (
25
- <input
26
- {...props}
27
- type={type}
28
- className={`border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-xs ${className}`}
29
- ref={localRef}
30
- />
31
- )
32
- })
@@ -1,37 +0,0 @@
1
- import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
2
- import DeleteUserForm from './Partials/DeleteUserForm'
3
- import UpdateAppearanceForm from './Partials/UpdateAppearanceForm'
4
- import UpdatePasswordForm from './Partials/UpdatePasswordForm'
5
- import UpdateProfileInformationForm from './Partials/UpdateProfileInformationForm'
6
- import { Head } from '@inertiajs/react'
7
- import { PageProps } from '@/types'
8
-
9
- export default function Edit({ mustVerifyEmail, status }: PageProps<{ mustVerifyEmail: boolean; status?: string }>) {
10
- return (
11
- <AuthenticatedLayout
12
- header={<h2 className="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">Profile</h2>}
13
- >
14
- <Head title="Profile" />
15
-
16
- <div className="py-12">
17
- <div className="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
18
- <div className="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow-sm sm:rounded-lg">
19
- <UpdateAppearanceForm className="max-w-xl" />
20
- </div>
21
-
22
- <div className="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow-sm sm:rounded-lg">
23
- <UpdateProfileInformationForm mustVerifyEmail={mustVerifyEmail} status={status} className="max-w-xl" />
24
- </div>
25
-
26
- <div className="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow-sm sm:rounded-lg">
27
- <UpdatePasswordForm className="max-w-xl" />
28
- </div>
29
-
30
- <div className="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow-sm sm:rounded-lg">
31
- <DeleteUserForm className="max-w-xl" />
32
- </div>
33
- </div>
34
- </div>
35
- </AuthenticatedLayout>
36
- )
37
- }
@@ -1,102 +0,0 @@
1
- import { useRef, useState, FormEventHandler } from 'react'
2
- import DangerButton from '@/Components/DangerButton'
3
- import InputError from '@/Components/InputError'
4
- import InputLabel from '@/Components/InputLabel'
5
- import Modal from '@/Components/Modal'
6
- import SecondaryButton from '@/Components/SecondaryButton'
7
- import TextInput from '@/Components/TextInput'
8
- import { useForm } from '@inertiajs/react'
9
- import { profile_destroy_path } from '@/routes'
10
-
11
- export default function DeleteUserForm({ className = '' }: { className?: string }) {
12
- const [confirmingUserDeletion, setConfirmingUserDeletion] = useState(false)
13
- const passwordInput = useRef<HTMLInputElement>(null)
14
-
15
- const {
16
- data,
17
- setData,
18
- delete: destroy,
19
- processing,
20
- reset,
21
- errors,
22
- clearErrors,
23
- } = useForm({
24
- password: '',
25
- })
26
-
27
- const confirmUserDeletion = () => {
28
- setConfirmingUserDeletion(true)
29
- }
30
-
31
- const deleteUser: FormEventHandler = (e) => {
32
- e.preventDefault()
33
-
34
- destroy(profile_destroy_path(), {
35
- preserveScroll: true,
36
- onSuccess: () => closeModal(),
37
- onError: () => passwordInput.current?.focus(),
38
- onFinish: () => reset(),
39
- })
40
- }
41
-
42
- const closeModal = () => {
43
- setConfirmingUserDeletion(false)
44
-
45
- clearErrors()
46
- reset()
47
- }
48
-
49
- return (
50
- <section className={`space-y-6 ${className}`}>
51
- <header>
52
- <h2 className="text-lg font-medium text-gray-900 dark:text-gray-100">Delete Account</h2>
53
-
54
- <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
55
- Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your
56
- account, please download any data or information that you wish to retain.
57
- </p>
58
- </header>
59
-
60
- <DangerButton onClick={confirmUserDeletion}>Delete Account</DangerButton>
61
-
62
- <Modal show={confirmingUserDeletion} onClose={closeModal}>
63
- <form onSubmit={deleteUser} className="p-6">
64
- <h2 className="text-lg font-medium text-gray-900 dark:text-gray-100">
65
- Are you sure you want to delete your account?
66
- </h2>
67
-
68
- <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
69
- Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your
70
- password to confirm you would like to permanently delete your account.
71
- </p>
72
-
73
- <div className="mt-6">
74
- <InputLabel htmlFor="password" value="Password" className="sr-only" />
75
-
76
- <TextInput
77
- id="password"
78
- type="password"
79
- name="password"
80
- ref={passwordInput}
81
- value={data.password}
82
- onChange={(e) => setData('password', e.target.value)}
83
- className="mt-1 block w-3/4"
84
- isFocused
85
- placeholder="Password"
86
- />
87
-
88
- <InputError message={errors.password} className="mt-2" />
89
- </div>
90
-
91
- <div className="mt-6 flex justify-end">
92
- <SecondaryButton onClick={closeModal}>Cancel</SecondaryButton>
93
-
94
- <DangerButton className="ms-3" disabled={processing}>
95
- Delete Account
96
- </DangerButton>
97
- </div>
98
- </form>
99
- </Modal>
100
- </section>
101
- )
102
- }
@@ -1,47 +0,0 @@
1
- import { useState } from 'react'
2
- import { Appearance, getAppearance, setAppearance } from '@/lib/appearance'
3
-
4
- const options: { value: Appearance; label: string }[] = [
5
- { value: 'light', label: 'Light' },
6
- { value: 'dark', label: 'Dark' },
7
- { value: 'system', label: 'System' },
8
- ]
9
-
10
- export default function UpdateAppearanceForm({ className = '' }: { className?: string }) {
11
- const [appearance, setCurrentAppearance] = useState<Appearance>(getAppearance)
12
-
13
- const select = (value: Appearance) => {
14
- setCurrentAppearance(value)
15
- setAppearance(value)
16
- }
17
-
18
- return (
19
- <section className={className}>
20
- <header>
21
- <h2 className="text-lg font-medium text-gray-900 dark:text-gray-100">Appearance</h2>
22
-
23
- <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
24
- Choose how the application looks to you. System follows your device setting.
25
- </p>
26
- </header>
27
-
28
- <div className="mt-6 inline-flex rounded-lg bg-gray-100 p-1 dark:bg-gray-900">
29
- {options.map((option) => (
30
- <button
31
- key={option.value}
32
- type="button"
33
- onClick={() => select(option.value)}
34
- aria-pressed={appearance === option.value}
35
- className={`rounded-md px-4 py-1.5 text-sm font-medium transition focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 ${
36
- appearance === option.value
37
- ? 'bg-white text-gray-900 shadow-xs dark:bg-gray-700 dark:text-gray-100'
38
- : 'text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100'
39
- }`}
40
- >
41
- {option.label}
42
- </button>
43
- ))}
44
- </div>
45
- </section>
46
- )
47
- }
@@ -1,29 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue'
3
-
4
- const emit = defineEmits(['update:checked'])
5
-
6
- const props = defineProps<{
7
- checked: boolean
8
- value?: any
9
- }>()
10
-
11
- const proxyChecked = computed({
12
- get() {
13
- return props.checked
14
- },
15
-
16
- set(val) {
17
- emit('update:checked', val)
18
- },
19
- })
20
- </script>
21
-
22
- <template>
23
- <input
24
- type="checkbox"
25
- :value="value"
26
- v-model="proxyChecked"
27
- class="rounded-sm dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-xs focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800"
28
- />
29
- </template>
@@ -1,7 +0,0 @@
1
- <template>
2
- <button
3
- class="inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-hidden focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150"
4
- >
5
- <slot />
6
- </button>
7
- </template>
@@ -1,75 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, onMounted, onUnmounted, ref } from 'vue'
3
-
4
- const props = withDefaults(
5
- defineProps<{
6
- align?: 'left' | 'right'
7
- width?: '48'
8
- contentClasses?: string
9
- }>(),
10
- {
11
- align: 'right',
12
- width: '48',
13
- contentClasses: 'py-1 bg-white dark:bg-gray-700',
14
- },
15
- )
16
-
17
- const closeOnEscape = (e: KeyboardEvent) => {
18
- if (open.value && e.key === 'Escape') {
19
- open.value = false
20
- }
21
- }
22
-
23
- onMounted(() => document.addEventListener('keydown', closeOnEscape))
24
- onUnmounted(() => document.removeEventListener('keydown', closeOnEscape))
25
-
26
- const widthClass = computed(() => {
27
- return {
28
- 48: 'w-48',
29
- }[props.width.toString()]
30
- })
31
-
32
- const alignmentClasses = computed(() => {
33
- if (props.align === 'left') {
34
- return 'ltr:origin-top-left rtl:origin-top-right start-0'
35
- } else if (props.align === 'right') {
36
- return 'ltr:origin-top-right rtl:origin-top-left end-0'
37
- } else {
38
- return 'origin-top'
39
- }
40
- })
41
-
42
- const open = ref(false)
43
- </script>
44
-
45
- <template>
46
- <div class="relative">
47
- <div @click="open = !open">
48
- <slot name="trigger" />
49
- </div>
50
-
51
- <!-- Full Screen Dropdown Overlay -->
52
- <div v-show="open" class="fixed inset-0 z-40" @click="open = false"></div>
53
-
54
- <Transition
55
- enter-active-class="transition ease-out duration-200"
56
- enter-from-class="opacity-0 scale-95"
57
- enter-to-class="opacity-100 scale-100"
58
- leave-active-class="transition ease-in duration-75"
59
- leave-from-class="opacity-100 scale-100"
60
- leave-to-class="opacity-0 scale-95"
61
- >
62
- <div
63
- v-show="open"
64
- class="absolute z-50 mt-2 rounded-md shadow-lg"
65
- :class="[widthClass, alignmentClasses]"
66
- style="display: none"
67
- @click="open = false"
68
- >
69
- <div class="rounded-md ring-1 ring-black ring-opacity-5" :class="contentClasses">
70
- <slot name="content" />
71
- </div>
72
- </div>
73
- </Transition>
74
- </div>
75
- </template>
@@ -1,16 +0,0 @@
1
- <script setup lang="ts">
2
- import { Link } from '@inertiajs/vue3'
3
-
4
- defineProps<{
5
- href: string
6
- }>()
7
- </script>
8
-
9
- <template>
10
- <Link
11
- :href="href"
12
- class="block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-hidden focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out"
13
- >
14
- <slot />
15
- </Link>
16
- </template>
@@ -1,12 +0,0 @@
1
- <script setup lang="ts">
2
- defineProps<{
3
- value?: string
4
- }>()
5
- </script>
6
-
7
- <template>
8
- <label class="block font-medium text-sm text-gray-700 dark:text-gray-300">
9
- <span v-if="value">{{ value }}</span>
10
- <span v-else><slot /></span>
11
- </label>
12
- </template>