kaze 1.3.1 → 2.0.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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/README.md +1 -1
  4. data/lib/kaze/commands/app/hotwire_stack.rb +2 -0
  5. data/lib/kaze/commands/app/inertia_react_stack.rb +5 -1
  6. data/lib/kaze/commands/app/inertia_vue_stack.rb +5 -1
  7. data/lib/kaze/commands/app.rb +9 -2
  8. data/lib/kaze/version.rb +1 -1
  9. data/stubs/default/config/routes.rb +11 -4
  10. data/stubs/default/test/integration/appearance_test.rb +11 -0
  11. data/stubs/default/test/integration/password_update_test.rb +9 -1
  12. data/stubs/hotwire/app/assets/tailwind/application.css +123 -0
  13. data/stubs/hotwire/app/components/breadcrumbs_component.rb +32 -0
  14. data/stubs/hotwire/app/components/danger_button_component.rb +1 -1
  15. data/stubs/hotwire/app/components/dropdown_component.html.erb +2 -2
  16. data/stubs/hotwire/app/components/dropdown_component.rb +5 -1
  17. data/stubs/hotwire/app/components/dropdown_link_component.rb +1 -1
  18. data/stubs/hotwire/app/components/heading_component.rb +19 -0
  19. data/stubs/hotwire/app/components/icon_component.rb +30 -0
  20. data/stubs/hotwire/app/components/input_error_component.rb +1 -1
  21. data/stubs/hotwire/app/components/input_label_component.rb +3 -3
  22. data/stubs/hotwire/app/components/modal_component.html.erb +2 -2
  23. data/stubs/hotwire/app/components/primary_button_component.rb +1 -1
  24. data/stubs/hotwire/app/components/secondary_button_component.rb +1 -1
  25. data/stubs/hotwire/app/components/sidebar_menu_button_component.rb +25 -0
  26. data/stubs/hotwire/app/components/text_input_component.rb +1 -1
  27. data/stubs/hotwire/app/components/user_avatar_component.rb +27 -0
  28. data/stubs/hotwire/app/controllers/application_controller.rb +1 -0
  29. data/stubs/hotwire/app/controllers/concerns/sidebar_state.rb +14 -0
  30. data/stubs/hotwire/app/controllers/settings/appearance_controller.rb +7 -0
  31. data/stubs/hotwire/app/controllers/settings/password_controller.rb +19 -0
  32. data/stubs/hotwire/app/controllers/{profile_controller.rb → settings/profile_controller.rb} +3 -4
  33. data/stubs/hotwire/app/views/auth/login.html.erb +1 -1
  34. data/stubs/hotwire/app/views/dashboard/index.html.erb +6 -11
  35. data/stubs/hotwire/app/views/layouts/_appearance.html.erb +18 -0
  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 +25 -15
  41. data/stubs/hotwire/app/views/layouts/guest.html.erb +1 -0
  42. data/stubs/hotwire/app/views/settings/appearance/_update_appearance_form.html.erb +28 -0
  43. data/stubs/hotwire/app/views/settings/appearance/edit.html.erb +10 -0
  44. data/stubs/hotwire/app/views/{profile/partials → settings/password}/_update_password_form.html.erb +2 -10
  45. data/stubs/hotwire/app/views/settings/password/edit.html.erb +10 -0
  46. data/stubs/hotwire/app/views/{profile/partials → settings/profile}/_confirm_user_deletion_modal.html.erb +2 -2
  47. data/stubs/hotwire/app/views/settings/profile/_delete_user_form.html.erb +6 -0
  48. data/stubs/hotwire/app/views/{profile/partials → settings/profile}/_update_profile_information_form.html.erb +4 -12
  49. data/stubs/hotwire/app/views/{profile → settings/profile}/destroy.turbo_stream.erb +1 -1
  50. data/stubs/hotwire/app/views/settings/profile/edit.html.erb +14 -0
  51. data/stubs/hotwire/app/views/welcome/index.html.erb +1 -0
  52. data/stubs/inertia-common/app/controllers/concerns/handle_inertia_requests.rb +4 -1
  53. data/stubs/inertia-common/app/controllers/settings/appearance_controller.rb +7 -0
  54. data/stubs/inertia-common/app/controllers/settings/password_controller.rb +17 -0
  55. data/stubs/inertia-common/app/controllers/{profile_controller.rb → settings/profile_controller.rb} +2 -2
  56. data/stubs/inertia-common/test/integration/appearance_test.rb +11 -0
  57. data/stubs/inertia-common/test/integration/password_update_test.rb +10 -2
  58. data/stubs/inertia-react-ts/app/assets/tailwind/application.css +124 -0
  59. data/stubs/inertia-react-ts/app/javascript/Components/AppLogo.tsx +17 -0
  60. data/stubs/inertia-react-ts/app/javascript/Components/AppShell.tsx +9 -0
  61. data/stubs/inertia-react-ts/app/javascript/Components/AppSidebar.tsx +65 -0
  62. data/stubs/inertia-react-ts/app/javascript/Components/AppSidebarHeader.tsx +14 -0
  63. data/stubs/inertia-react-ts/app/javascript/Components/Breadcrumbs.tsx +43 -0
  64. data/stubs/inertia-react-ts/app/javascript/Components/Heading.tsx +19 -0
  65. data/stubs/inertia-react-ts/app/javascript/Components/InputError.tsx +1 -1
  66. data/stubs/inertia-react-ts/app/javascript/Components/NavFooter.tsx +32 -0
  67. data/stubs/inertia-react-ts/app/javascript/Components/NavMain.tsx +32 -0
  68. data/stubs/inertia-react-ts/app/javascript/Components/NavUser.tsx +39 -0
  69. data/stubs/inertia-react-ts/app/javascript/Components/UserInfo.tsx +23 -0
  70. data/stubs/inertia-react-ts/app/javascript/Components/UserMenuContent.tsx +57 -0
  71. data/stubs/inertia-react-ts/app/javascript/Components/ui/avatar.tsx +51 -0
  72. data/stubs/inertia-react-ts/app/javascript/Components/ui/breadcrumb.tsx +109 -0
  73. data/stubs/inertia-react-ts/app/javascript/Components/ui/button.tsx +49 -0
  74. data/stubs/inertia-react-ts/app/javascript/Components/ui/checkbox.tsx +27 -0
  75. data/stubs/inertia-react-ts/app/javascript/Components/ui/dialog.tsx +109 -0
  76. data/stubs/inertia-react-ts/app/javascript/Components/ui/dropdown-menu.tsx +217 -0
  77. data/stubs/inertia-react-ts/app/javascript/Components/ui/input.tsx +21 -0
  78. data/stubs/inertia-react-ts/app/javascript/Components/ui/label.tsx +19 -0
  79. data/stubs/inertia-react-ts/app/javascript/Components/ui/separator.tsx +26 -0
  80. data/stubs/inertia-react-ts/app/javascript/Components/ui/sheet.tsx +137 -0
  81. data/stubs/inertia-react-ts/app/javascript/Components/ui/sidebar.tsx +719 -0
  82. data/stubs/inertia-react-ts/app/javascript/Components/ui/skeleton.tsx +13 -0
  83. data/stubs/inertia-react-ts/app/javascript/Components/ui/tooltip.tsx +55 -0
  84. data/stubs/inertia-react-ts/app/javascript/Layouts/AuthenticatedLayout.tsx +19 -127
  85. data/stubs/inertia-react-ts/app/javascript/Layouts/GuestLayout.tsx +2 -2
  86. data/stubs/inertia-react-ts/app/javascript/Layouts/SettingsLayout.tsx +57 -0
  87. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ForgotPassword.tsx +6 -6
  88. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Login.tsx +17 -12
  89. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/Register.tsx +14 -14
  90. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/ResetPassword.tsx +10 -10
  91. data/stubs/inertia-react-ts/app/javascript/Pages/Auth/VerifyEmail.tsx +2 -2
  92. data/stubs/inertia-react-ts/app/javascript/Pages/Dashboard.tsx +13 -8
  93. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Appearance.tsx +33 -0
  94. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Partials/DeleteUserForm.tsx +107 -0
  95. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Partials/UpdateAppearanceForm.tsx +41 -0
  96. data/stubs/inertia-react-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdatePasswordForm.tsx +12 -20
  97. data/stubs/inertia-react-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdateProfileInformationForm.tsx +13 -21
  98. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Password.tsx +33 -0
  99. data/stubs/inertia-react-ts/app/javascript/Pages/Settings/Profile.tsx +35 -0
  100. data/stubs/inertia-react-ts/app/javascript/entrypoints/application.tsx +6 -1
  101. data/stubs/inertia-react-ts/app/javascript/hooks/use-initials.tsx +23 -0
  102. data/stubs/inertia-react-ts/app/javascript/hooks/use-mobile-navigation.tsx +11 -0
  103. data/stubs/inertia-react-ts/app/javascript/hooks/use-mobile.tsx +36 -0
  104. data/stubs/inertia-react-ts/app/javascript/lib/appearance.ts +22 -0
  105. data/stubs/inertia-react-ts/app/javascript/lib/utils.ts +6 -0
  106. data/stubs/inertia-react-ts/app/javascript/types/global.d.ts +2 -2
  107. data/stubs/inertia-react-ts/app/javascript/types/index.d.ts +14 -0
  108. data/stubs/inertia-react-ts/app/views/layouts/application.html.erb +19 -1
  109. data/stubs/inertia-react-ts/components.json +21 -0
  110. data/stubs/inertia-react-ts/package.json +13 -0
  111. data/stubs/inertia-vue-ts/app/assets/tailwind/application.css +124 -0
  112. data/stubs/inertia-vue-ts/app/javascript/Components/AppLogo.vue +17 -0
  113. data/stubs/inertia-vue-ts/app/javascript/Components/AppShell.vue +12 -0
  114. data/stubs/inertia-vue-ts/app/javascript/Components/AppSidebar.vue +65 -0
  115. data/stubs/inertia-vue-ts/app/javascript/Components/AppSidebarHeader.vue +20 -0
  116. data/stubs/inertia-vue-ts/app/javascript/Components/Breadcrumbs.vue +32 -0
  117. data/stubs/inertia-vue-ts/app/javascript/Components/Heading.vue +15 -0
  118. data/stubs/inertia-vue-ts/app/javascript/Components/InputError.vue +1 -1
  119. data/stubs/inertia-vue-ts/app/javascript/Components/NavFooter.vue +33 -0
  120. data/stubs/inertia-vue-ts/app/javascript/Components/NavMain.vue +32 -0
  121. data/stubs/inertia-vue-ts/app/javascript/Components/NavUser.vue +40 -0
  122. data/stubs/inertia-vue-ts/app/javascript/Components/UserInfo.vue +25 -0
  123. data/stubs/inertia-vue-ts/app/javascript/Components/UserMenuContent.vue +47 -0
  124. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/Avatar.vue +18 -0
  125. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/AvatarFallback.vue +21 -0
  126. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/AvatarImage.vue +16 -0
  127. data/stubs/inertia-vue-ts/app/javascript/Components/ui/avatar/index.ts +3 -0
  128. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/Breadcrumb.vue +17 -0
  129. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbEllipsis.vue +23 -0
  130. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
  131. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbLink.vue +21 -0
  132. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbList.vue +17 -0
  133. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
  134. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/BreadcrumbSeparator.vue +22 -0
  135. data/stubs/inertia-vue-ts/app/javascript/Components/ui/breadcrumb/index.ts +7 -0
  136. data/stubs/inertia-vue-ts/app/javascript/Components/ui/button/Button.vue +31 -0
  137. data/stubs/inertia-vue-ts/app/javascript/Components/ui/button/index.ts +34 -0
  138. data/stubs/inertia-vue-ts/app/javascript/Components/ui/checkbox/Checkbox.vue +35 -0
  139. data/stubs/inertia-vue-ts/app/javascript/Components/ui/checkbox/index.ts +1 -0
  140. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/Dialog.vue +15 -0
  141. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogClose.vue +12 -0
  142. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogContent.vue +52 -0
  143. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogDescription.vue +23 -0
  144. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogFooter.vue +25 -0
  145. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogHeader.vue +14 -0
  146. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogOverlay.vue +26 -0
  147. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogTitle.vue +23 -0
  148. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/DialogTrigger.vue +12 -0
  149. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dialog/index.ts +9 -0
  150. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenu.vue +15 -0
  151. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuContent.vue +37 -0
  152. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  153. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
  154. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -0
  155. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  156. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/DropdownMenuTrigger.vue +14 -0
  157. data/stubs/inertia-vue-ts/app/javascript/Components/ui/dropdown-menu/index.ts +7 -0
  158. data/stubs/inertia-vue-ts/app/javascript/Components/ui/input/Input.vue +50 -0
  159. data/stubs/inertia-vue-ts/app/javascript/Components/ui/input/index.ts +1 -0
  160. data/stubs/inertia-vue-ts/app/javascript/Components/ui/label/Label.vue +26 -0
  161. data/stubs/inertia-vue-ts/app/javascript/Components/ui/label/index.ts +1 -0
  162. data/stubs/inertia-vue-ts/app/javascript/Components/ui/separator/Separator.vue +29 -0
  163. data/stubs/inertia-vue-ts/app/javascript/Components/ui/separator/index.ts +1 -0
  164. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/Sheet.vue +19 -0
  165. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetClose.vue +15 -0
  166. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetContent.vue +62 -0
  167. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetDescription.vue +21 -0
  168. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetFooter.vue +16 -0
  169. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetHeader.vue +15 -0
  170. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetOverlay.vue +21 -0
  171. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetTitle.vue +21 -0
  172. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/SheetTrigger.vue +15 -0
  173. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sheet/index.ts +8 -0
  174. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/Sidebar.vue +96 -0
  175. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarContent.vue +18 -0
  176. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarFooter.vue +18 -0
  177. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroup.vue +18 -0
  178. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroupAction.vue +27 -0
  179. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroupContent.vue +18 -0
  180. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarGroupLabel.vue +25 -0
  181. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarHeader.vue +18 -0
  182. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarInput.vue +22 -0
  183. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarInset.vue +21 -0
  184. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenu.vue +18 -0
  185. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuAction.vue +35 -0
  186. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuBadge.vue +26 -0
  187. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuButton.vue +48 -0
  188. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
  189. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuItem.vue +18 -0
  190. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
  191. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSub.vue +22 -0
  192. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSubButton.vue +36 -0
  193. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
  194. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarProvider.vue +82 -0
  195. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarRail.vue +33 -0
  196. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarSeparator.vue +19 -0
  197. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/SidebarTrigger.vue +28 -0
  198. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/index.ts +60 -0
  199. data/stubs/inertia-vue-ts/app/javascript/Components/ui/sidebar/utils.ts +19 -0
  200. data/stubs/inertia-vue-ts/app/javascript/Components/ui/skeleton/Skeleton.vue +17 -0
  201. data/stubs/inertia-vue-ts/app/javascript/Components/ui/skeleton/index.ts +1 -0
  202. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/Tooltip.vue +19 -0
  203. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/TooltipContent.vue +34 -0
  204. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/TooltipProvider.vue +14 -0
  205. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/TooltipTrigger.vue +15 -0
  206. data/stubs/inertia-vue-ts/app/javascript/Components/ui/tooltip/index.ts +4 -0
  207. data/stubs/inertia-vue-ts/app/javascript/Layouts/AuthenticatedLayout.vue +17 -147
  208. data/stubs/inertia-vue-ts/app/javascript/Layouts/SettingsLayout.vue +57 -0
  209. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ForgotPassword.vue +7 -7
  210. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Login.vue +10 -12
  211. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/Register.vue +12 -14
  212. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/ResetPassword.vue +8 -10
  213. data/stubs/inertia-vue-ts/app/javascript/Pages/Auth/VerifyEmail.vue +3 -3
  214. data/stubs/inertia-vue-ts/app/javascript/Pages/Dashboard.vue +15 -10
  215. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Appearance.vue +33 -0
  216. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Partials/DeleteUserForm.vue +96 -0
  217. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Partials/UpdateAppearanceForm.vue +42 -0
  218. data/stubs/inertia-vue-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdatePasswordForm.vue +12 -20
  219. data/stubs/inertia-vue-ts/app/javascript/Pages/{Profile → Settings}/Partials/UpdateProfileInformationForm.vue +12 -20
  220. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Password.vue +33 -0
  221. data/stubs/inertia-vue-ts/app/javascript/Pages/Settings/Profile.vue +40 -0
  222. data/stubs/inertia-vue-ts/app/javascript/composables/useInitials.ts +29 -0
  223. data/stubs/inertia-vue-ts/app/javascript/lib/appearance.ts +22 -0
  224. data/stubs/inertia-vue-ts/app/javascript/lib/utils.ts +6 -0
  225. data/stubs/inertia-vue-ts/app/javascript/types/index.d.ts +14 -0
  226. data/stubs/inertia-vue-ts/app/javascript/types/vue-shims.d.ts +10 -0
  227. data/stubs/inertia-vue-ts/app/views/layouts/application.html.erb +19 -1
  228. data/stubs/inertia-vue-ts/components.json +20 -0
  229. data/stubs/inertia-vue-ts/package.json +8 -1
  230. data/stubs/inertia-vue-ts/vite.config.ts +25 -1
  231. metadata +174 -43
  232. data/stubs/hotwire/app/components/nav_link_component.rb +0 -15
  233. data/stubs/hotwire/app/components/responsive_nav_link_component.rb +0 -15
  234. data/stubs/hotwire/app/controllers/password_controller.rb +0 -13
  235. data/stubs/hotwire/app/views/layouts/_navigation.html.erb +0 -82
  236. data/stubs/hotwire/app/views/profile/edit.html.erb +0 -24
  237. data/stubs/hotwire/app/views/profile/partials/_delete_user_form.html.erb +0 -14
  238. data/stubs/inertia-common/app/controllers/password_controller.rb +0 -13
  239. data/stubs/inertia-react-ts/app/javascript/Components/Checkbox.tsx +0 -11
  240. data/stubs/inertia-react-ts/app/javascript/Components/DangerButton.tsx +0 -20
  241. data/stubs/inertia-react-ts/app/javascript/Components/Dropdown.tsx +0 -100
  242. data/stubs/inertia-react-ts/app/javascript/Components/InputLabel.tsx +0 -14
  243. data/stubs/inertia-react-ts/app/javascript/Components/Modal.tsx +0 -66
  244. data/stubs/inertia-react-ts/app/javascript/Components/NavLink.tsx +0 -21
  245. data/stubs/inertia-react-ts/app/javascript/Components/PrimaryButton.tsx +0 -20
  246. data/stubs/inertia-react-ts/app/javascript/Components/ResponsiveNavLink.tsx +0 -21
  247. data/stubs/inertia-react-ts/app/javascript/Components/SecondaryButton.tsx +0 -22
  248. data/stubs/inertia-react-ts/app/javascript/Components/TextInput.tsx +0 -32
  249. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Edit.tsx +0 -32
  250. data/stubs/inertia-react-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.tsx +0 -102
  251. data/stubs/inertia-vue-ts/app/javascript/Components/Checkbox.vue +0 -29
  252. data/stubs/inertia-vue-ts/app/javascript/Components/DangerButton.vue +0 -7
  253. data/stubs/inertia-vue-ts/app/javascript/Components/Dropdown.vue +0 -75
  254. data/stubs/inertia-vue-ts/app/javascript/Components/DropdownLink.vue +0 -16
  255. data/stubs/inertia-vue-ts/app/javascript/Components/InputLabel.vue +0 -12
  256. data/stubs/inertia-vue-ts/app/javascript/Components/Modal.vue +0 -109
  257. data/stubs/inertia-vue-ts/app/javascript/Components/NavLink.vue +0 -21
  258. data/stubs/inertia-vue-ts/app/javascript/Components/PrimaryButton.vue +0 -7
  259. data/stubs/inertia-vue-ts/app/javascript/Components/ResponsiveNavLink.vue +0 -21
  260. data/stubs/inertia-vue-ts/app/javascript/Components/SecondaryButton.vue +0 -19
  261. data/stubs/inertia-vue-ts/app/javascript/Components/TextInput.vue +0 -23
  262. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Edit.vue +0 -38
  263. data/stubs/inertia-vue-ts/app/javascript/Pages/Profile/Partials/DeleteUserForm.vue +0 -99
@@ -1,4 +1,128 @@
1
1
  @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ /* Drive `dark:` from a `dark` class rather than prefers-color-scheme, so the
5
+ appearance preference can override the operating system. The layouts apply
6
+ the class before first paint. */
7
+ @custom-variant dark (&:is(.dark *));
8
+
9
+ @theme inline {
10
+ --color-background: var(--background);
11
+ --color-foreground: var(--foreground);
12
+
13
+ --color-card: var(--card);
14
+ --color-card-foreground: var(--card-foreground);
15
+
16
+ --color-popover: var(--popover);
17
+ --color-popover-foreground: var(--popover-foreground);
18
+
19
+ --color-primary: var(--primary);
20
+ --color-primary-foreground: var(--primary-foreground);
21
+
22
+ --color-secondary: var(--secondary);
23
+ --color-secondary-foreground: var(--secondary-foreground);
24
+
25
+ --color-muted: var(--muted);
26
+ --color-muted-foreground: var(--muted-foreground);
27
+
28
+ --color-accent: var(--accent);
29
+ --color-accent-foreground: var(--accent-foreground);
30
+
31
+ --color-destructive: var(--destructive);
32
+ --color-destructive-foreground: var(--destructive-foreground);
33
+
34
+ --color-border: var(--border);
35
+ --color-input: var(--input);
36
+ --color-ring: var(--ring);
37
+
38
+ --color-sidebar: var(--sidebar);
39
+ --color-sidebar-foreground: var(--sidebar-foreground);
40
+ --color-sidebar-primary: var(--sidebar-primary);
41
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
42
+ --color-sidebar-accent: var(--sidebar-accent);
43
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
44
+ --color-sidebar-border: var(--sidebar-border);
45
+ --color-sidebar-ring: var(--sidebar-ring);
46
+
47
+ --radius-sm: calc(var(--radius) - 4px);
48
+ --radius-md: calc(var(--radius) - 2px);
49
+ --radius-lg: var(--radius);
50
+ --radius-xl: calc(var(--radius) + 4px);
51
+ }
52
+
53
+ :root {
54
+ --radius: 0.625rem;
55
+
56
+ --background: oklch(1 0 0);
57
+ --foreground: oklch(0.145 0 0);
58
+ --card: oklch(1 0 0);
59
+ --card-foreground: oklch(0.145 0 0);
60
+ --popover: oklch(1 0 0);
61
+ --popover-foreground: oklch(0.145 0 0);
62
+ --primary: oklch(0.205 0 0);
63
+ --primary-foreground: oklch(0.985 0 0);
64
+ --secondary: oklch(0.97 0 0);
65
+ --secondary-foreground: oklch(0.205 0 0);
66
+ --muted: oklch(0.97 0 0);
67
+ --muted-foreground: oklch(0.556 0 0);
68
+ --accent: oklch(0.97 0 0);
69
+ --accent-foreground: oklch(0.205 0 0);
70
+ --destructive: oklch(0.577 0.245 27.325);
71
+ --destructive-foreground: oklch(0.985 0 0);
72
+ --border: oklch(0.922 0 0);
73
+ --input: oklch(0.922 0 0);
74
+ --ring: oklch(0.87 0 0);
75
+
76
+ --sidebar: oklch(0.985 0 0);
77
+ --sidebar-foreground: oklch(0.145 0 0);
78
+ --sidebar-primary: oklch(0.205 0 0);
79
+ --sidebar-primary-foreground: oklch(0.985 0 0);
80
+ --sidebar-accent: oklch(0.97 0 0);
81
+ --sidebar-accent-foreground: oklch(0.205 0 0);
82
+ --sidebar-border: oklch(0.922 0 0);
83
+ --sidebar-ring: oklch(0.87 0 0);
84
+ }
85
+
86
+ .dark {
87
+ --background: oklch(0.145 0 0);
88
+ --foreground: oklch(0.985 0 0);
89
+ --card: oklch(0.145 0 0);
90
+ --card-foreground: oklch(0.985 0 0);
91
+ --popover: oklch(0.145 0 0);
92
+ --popover-foreground: oklch(0.985 0 0);
93
+ --primary: oklch(0.985 0 0);
94
+ --primary-foreground: oklch(0.205 0 0);
95
+ --secondary: oklch(0.269 0 0);
96
+ --secondary-foreground: oklch(0.985 0 0);
97
+ --muted: oklch(0.269 0 0);
98
+ --muted-foreground: oklch(0.708 0 0);
99
+ --accent: oklch(0.269 0 0);
100
+ --accent-foreground: oklch(0.985 0 0);
101
+ --destructive: oklch(0.396 0.141 25.723);
102
+ --destructive-foreground: oklch(0.985 0 0);
103
+ --border: oklch(0.269 0 0);
104
+ --input: oklch(0.269 0 0);
105
+ --ring: oklch(0.439 0 0);
106
+
107
+ --sidebar: oklch(0.205 0 0);
108
+ --sidebar-foreground: oklch(0.985 0 0);
109
+ --sidebar-primary: oklch(0.985 0 0);
110
+ --sidebar-primary-foreground: oklch(0.985 0 0);
111
+ --sidebar-accent: oklch(0.269 0 0);
112
+ --sidebar-accent-foreground: oklch(0.985 0 0);
113
+ --sidebar-border: oklch(0.269 0 0);
114
+ --sidebar-ring: oklch(0.439 0 0);
115
+ }
116
+
117
+ @layer base {
118
+ * {
119
+ @apply border-border outline-ring/50;
120
+ }
121
+
122
+ body {
123
+ @apply bg-background text-foreground;
124
+ }
125
+ }
2
126
 
3
127
  @plugin "@tailwindcss/forms";
4
128
 
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import ApplicationLogo from '@/Components/ApplicationLogo.vue'
3
+
4
+ const appName = import.meta.env.VITE_APP_NAME || 'Rails'
5
+ </script>
6
+
7
+ <template>
8
+ <div
9
+ class="flex aspect-square size-8 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground"
10
+ >
11
+ <ApplicationLogo class="size-5 fill-current text-white dark:text-black" />
12
+ </div>
13
+
14
+ <div class="ml-1 grid flex-1 text-left text-sm">
15
+ <span class="mb-0.5 truncate leading-tight font-semibold">{{ appName }}</span>
16
+ </div>
17
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import { usePage } from '@inertiajs/vue3'
3
+ import { SidebarProvider } from '@/Components/ui/sidebar'
4
+
5
+ const sidebarOpen = usePage().props.sidebar_open
6
+ </script>
7
+
8
+ <template>
9
+ <SidebarProvider :default-open="sidebarOpen">
10
+ <slot />
11
+ </SidebarProvider>
12
+ </template>
@@ -0,0 +1,65 @@
1
+ <script setup lang="ts">
2
+ import { Link } from '@inertiajs/vue3'
3
+ import { BookOpen, FolderGit2, LayoutGrid } from '@lucide/vue'
4
+ import AppLogo from '@/Components/AppLogo.vue'
5
+ import NavFooter from '@/Components/NavFooter.vue'
6
+ import NavMain from '@/Components/NavMain.vue'
7
+ import NavUser from '@/Components/NavUser.vue'
8
+ import {
9
+ Sidebar,
10
+ SidebarContent,
11
+ SidebarFooter,
12
+ SidebarHeader,
13
+ SidebarMenu,
14
+ SidebarMenuButton,
15
+ SidebarMenuItem,
16
+ } from '@/Components/ui/sidebar'
17
+ import { dashboard_path } from '@/routes'
18
+ import { NavItem } from '@/types'
19
+
20
+ const mainNavItems: NavItem[] = [
21
+ {
22
+ title: 'Dashboard',
23
+ href: dashboard_path(),
24
+ icon: LayoutGrid,
25
+ },
26
+ ]
27
+
28
+ const footerNavItems: NavItem[] = [
29
+ {
30
+ title: 'Repository',
31
+ href: 'https://github.com/cuonggt/kaze',
32
+ icon: FolderGit2,
33
+ },
34
+ {
35
+ title: 'Documentation',
36
+ href: 'https://github.com/cuonggt/kaze#readme',
37
+ icon: BookOpen,
38
+ },
39
+ ]
40
+ </script>
41
+
42
+ <template>
43
+ <Sidebar collapsible="icon" variant="inset">
44
+ <SidebarHeader>
45
+ <SidebarMenu>
46
+ <SidebarMenuItem>
47
+ <SidebarMenuButton size="lg" as-child>
48
+ <Link :href="dashboard_path()">
49
+ <AppLogo />
50
+ </Link>
51
+ </SidebarMenuButton>
52
+ </SidebarMenuItem>
53
+ </SidebarMenu>
54
+ </SidebarHeader>
55
+
56
+ <SidebarContent>
57
+ <NavMain :items="mainNavItems" />
58
+ </SidebarContent>
59
+
60
+ <SidebarFooter>
61
+ <NavFooter :items="footerNavItems" class="mt-auto" />
62
+ <NavUser />
63
+ </SidebarFooter>
64
+ </Sidebar>
65
+ </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import Breadcrumbs from '@/Components/Breadcrumbs.vue'
3
+ import { SidebarTrigger } from '@/Components/ui/sidebar'
4
+ import { BreadcrumbItem } from '@/types'
5
+
6
+ withDefaults(defineProps<{ breadcrumbs?: BreadcrumbItem[] }>(), {
7
+ breadcrumbs: () => [],
8
+ })
9
+ </script>
10
+
11
+ <template>
12
+ <header
13
+ class="flex h-16 shrink-0 items-center gap-2 border-b border-sidebar-border/50 px-6 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12 md:px-4"
14
+ >
15
+ <div class="flex items-center gap-2">
16
+ <SidebarTrigger class="-ml-1" />
17
+ <Breadcrumbs :breadcrumbs="breadcrumbs" />
18
+ </div>
19
+ </header>
20
+ </template>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import { Link } from '@inertiajs/vue3'
3
+ import {
4
+ Breadcrumb,
5
+ BreadcrumbItem,
6
+ BreadcrumbLink,
7
+ BreadcrumbList,
8
+ BreadcrumbPage,
9
+ BreadcrumbSeparator,
10
+ } from '@/Components/ui/breadcrumb'
11
+ import { BreadcrumbItem as BreadcrumbItemType } from '@/types'
12
+
13
+ defineProps<{ breadcrumbs: BreadcrumbItemType[] }>()
14
+ </script>
15
+
16
+ <template>
17
+ <Breadcrumb v-if="breadcrumbs.length > 0">
18
+ <BreadcrumbList>
19
+ <template v-for="(item, index) in breadcrumbs" :key="item.href">
20
+ <BreadcrumbItem>
21
+ <BreadcrumbPage v-if="index === breadcrumbs.length - 1">{{ item.title }}</BreadcrumbPage>
22
+
23
+ <BreadcrumbLink v-else as-child>
24
+ <Link :href="item.href">{{ item.title }}</Link>
25
+ </BreadcrumbLink>
26
+ </BreadcrumbItem>
27
+
28
+ <BreadcrumbSeparator v-if="index !== breadcrumbs.length - 1" />
29
+ </template>
30
+ </BreadcrumbList>
31
+ </Breadcrumb>
32
+ </template>
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ withDefaults(defineProps<{ title: string; description?: string; variant?: 'default' | 'small' }>(), {
3
+ variant: 'default',
4
+ })
5
+ </script>
6
+
7
+ <template>
8
+ <header :class="variant === 'small' ? '' : 'mb-8 space-y-0.5'">
9
+ <h2 :class="variant === 'small' ? 'mb-0.5 text-base font-medium' : 'text-xl font-semibold tracking-tight'">
10
+ {{ title }}
11
+ </h2>
12
+
13
+ <p v-if="description" class="text-sm text-muted-foreground">{{ description }}</p>
14
+ </header>
15
+ </template>
@@ -6,7 +6,7 @@ defineProps<{
6
6
 
7
7
  <template>
8
8
  <div v-show="message">
9
- <p class="text-sm text-red-600 dark:text-red-400">
9
+ <p class="text-sm text-destructive">
10
10
  {{ message }}
11
11
  </p>
12
12
  </div>
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ SidebarGroup,
4
+ SidebarGroupContent,
5
+ SidebarMenu,
6
+ SidebarMenuButton,
7
+ SidebarMenuItem,
8
+ } from '@/Components/ui/sidebar'
9
+ import { cn } from '@/lib/utils'
10
+ import { NavItem } from '@/types'
11
+
12
+ const props = defineProps<{ items: NavItem[]; class?: string }>()
13
+ </script>
14
+
15
+ <template>
16
+ <SidebarGroup :class="cn('group-data-[collapsible=icon]:p-0', props.class)">
17
+ <SidebarGroupContent>
18
+ <SidebarMenu>
19
+ <SidebarMenuItem v-for="item in items" :key="item.title">
20
+ <SidebarMenuButton
21
+ as-child
22
+ class="text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100"
23
+ >
24
+ <a :href="item.href" target="_blank" rel="noopener noreferrer">
25
+ <component :is="item.icon" v-if="item.icon" class="h-5 w-5" />
26
+ <span>{{ item.title }}</span>
27
+ </a>
28
+ </SidebarMenuButton>
29
+ </SidebarMenuItem>
30
+ </SidebarMenu>
31
+ </SidebarGroupContent>
32
+ </SidebarGroup>
33
+ </template>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import { Link, usePage } from '@inertiajs/vue3'
3
+ import {
4
+ SidebarGroup,
5
+ SidebarGroupLabel,
6
+ SidebarMenu,
7
+ SidebarMenuButton,
8
+ SidebarMenuItem,
9
+ } from '@/Components/ui/sidebar'
10
+ import { NavItem } from '@/types'
11
+
12
+ defineProps<{ items: NavItem[] }>()
13
+
14
+ const page = usePage()
15
+ </script>
16
+
17
+ <template>
18
+ <SidebarGroup class="px-2 py-0">
19
+ <SidebarGroupLabel>Platform</SidebarGroupLabel>
20
+
21
+ <SidebarMenu>
22
+ <SidebarMenuItem v-for="item in items" :key="item.title">
23
+ <SidebarMenuButton as-child :is-active="page.url.startsWith(item.href)" :tooltip="item.title">
24
+ <Link :href="item.href">
25
+ <component :is="item.icon" v-if="item.icon" />
26
+ <span>{{ item.title }}</span>
27
+ </Link>
28
+ </SidebarMenuButton>
29
+ </SidebarMenuItem>
30
+ </SidebarMenu>
31
+ </SidebarGroup>
32
+ </template>
@@ -0,0 +1,40 @@
1
+ <script setup lang="ts">
2
+ import { usePage } from '@inertiajs/vue3'
3
+ import { ChevronsUpDown } from '@lucide/vue'
4
+ import { computed } from 'vue'
5
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from '@/Components/ui/dropdown-menu'
6
+ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, useSidebar } from '@/Components/ui/sidebar'
7
+ import UserInfo from '@/Components/UserInfo.vue'
8
+ import UserMenuContent from '@/Components/UserMenuContent.vue'
9
+
10
+ const page = usePage()
11
+ const user = computed(() => page.props.auth.user)
12
+ const { isMobile, state } = useSidebar()
13
+ </script>
14
+
15
+ <template>
16
+ <SidebarMenu>
17
+ <SidebarMenuItem>
18
+ <DropdownMenu>
19
+ <DropdownMenuTrigger as-child>
20
+ <SidebarMenuButton
21
+ size="lg"
22
+ class="group text-sidebar-accent-foreground data-[state=open]:bg-sidebar-accent"
23
+ >
24
+ <UserInfo :user="user" />
25
+ <ChevronsUpDown class="ml-auto size-4" />
26
+ </SidebarMenuButton>
27
+ </DropdownMenuTrigger>
28
+
29
+ <DropdownMenuContent
30
+ class="w-(--reka-dropdown-menu-trigger-width) min-w-56 rounded-lg"
31
+ :side="isMobile ? 'bottom' : state === 'collapsed' ? 'left' : 'bottom'"
32
+ align="end"
33
+ :side-offset="4"
34
+ >
35
+ <UserMenuContent :user="user" />
36
+ </DropdownMenuContent>
37
+ </DropdownMenu>
38
+ </SidebarMenuItem>
39
+ </SidebarMenu>
40
+ </template>
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ import { Avatar, AvatarFallback } from '@/Components/ui/avatar'
3
+ import { useInitials } from '@/composables/useInitials'
4
+ import { User } from '@/types'
5
+
6
+ withDefaults(defineProps<{ user: User; showEmail?: boolean }>(), {
7
+ showEmail: false,
8
+ })
9
+
10
+ const { getInitials } = useInitials()
11
+ </script>
12
+
13
+ <template>
14
+ <Avatar class="h-8 w-8 overflow-hidden rounded-full">
15
+ <AvatarFallback class="rounded-lg bg-neutral-200 text-black dark:bg-neutral-700 dark:text-white">
16
+ {{ getInitials(user.name) }}
17
+ </AvatarFallback>
18
+ </Avatar>
19
+
20
+ <div class="grid flex-1 text-left text-sm leading-tight">
21
+ <span class="truncate font-medium">{{ user.name }}</span>
22
+
23
+ <span v-if="showEmail" class="truncate text-xs text-muted-foreground">{{ user.email }}</span>
24
+ </div>
25
+ </template>
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import { Link, router } from '@inertiajs/vue3'
3
+ import { LogOut, Settings } from '@lucide/vue'
4
+ import {
5
+ DropdownMenuGroup,
6
+ DropdownMenuItem,
7
+ DropdownMenuLabel,
8
+ DropdownMenuSeparator,
9
+ } from '@/Components/ui/dropdown-menu'
10
+ import UserInfo from '@/Components/UserInfo.vue'
11
+ import { logout_path, profile_edit_path } from '@/routes'
12
+ import { User } from '@/types'
13
+
14
+ defineProps<{ user: User }>()
15
+
16
+ const handleLogout = () => {
17
+ router.flushAll()
18
+ }
19
+ </script>
20
+
21
+ <template>
22
+ <DropdownMenuLabel class="p-0 font-normal">
23
+ <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
24
+ <UserInfo :user="user" show-email />
25
+ </div>
26
+ </DropdownMenuLabel>
27
+
28
+ <DropdownMenuSeparator />
29
+
30
+ <DropdownMenuGroup>
31
+ <DropdownMenuItem as-child>
32
+ <Link class="block w-full cursor-pointer" :href="profile_edit_path()">
33
+ <Settings class="mr-2 h-4 w-4" />
34
+ Settings
35
+ </Link>
36
+ </DropdownMenuItem>
37
+ </DropdownMenuGroup>
38
+
39
+ <DropdownMenuSeparator />
40
+
41
+ <DropdownMenuItem as-child>
42
+ <Link class="block w-full cursor-pointer" :href="logout_path()" method="post" as="button" @click="handleLogout">
43
+ <LogOut class="mr-2 h-4 w-4" />
44
+ Log out
45
+ </Link>
46
+ </DropdownMenuItem>
47
+ </template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { AvatarRoot } from "reka-ui"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes["class"]
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <AvatarRoot
13
+ data-slot="avatar"
14
+ :class="cn('relative flex size-8 shrink-0 overflow-hidden rounded-full', props.class)"
15
+ >
16
+ <slot />
17
+ </AvatarRoot>
18
+ </template>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import type { AvatarFallbackProps } from "reka-ui"
3
+ import type { HTMLAttributes } from "vue"
4
+ import { reactiveOmit } from "@vueuse/core"
5
+ import { AvatarFallback } from "reka-ui"
6
+ import { cn } from "@/lib/utils"
7
+
8
+ const props = defineProps<AvatarFallbackProps & { class?: HTMLAttributes["class"] }>()
9
+
10
+ const delegatedProps = reactiveOmit(props, "class")
11
+ </script>
12
+
13
+ <template>
14
+ <AvatarFallback
15
+ data-slot="avatar-fallback"
16
+ v-bind="delegatedProps"
17
+ :class="cn('bg-muted flex size-full items-center justify-center rounded-full', props.class)"
18
+ >
19
+ <slot />
20
+ </AvatarFallback>
21
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import type { AvatarImageProps } from "reka-ui"
3
+ import { AvatarImage } from "reka-ui"
4
+
5
+ const props = defineProps<AvatarImageProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <AvatarImage
10
+ data-slot="avatar-image"
11
+ v-bind="props"
12
+ class="aspect-square size-full"
13
+ >
14
+ <slot />
15
+ </AvatarImage>
16
+ </template>
@@ -0,0 +1,3 @@
1
+ export { default as Avatar } from "./Avatar.vue"
2
+ export { default as AvatarFallback } from "./AvatarFallback.vue"
3
+ export { default as AvatarImage } from "./AvatarImage.vue"
@@ -0,0 +1,17 @@
1
+ <script lang="ts" setup>
2
+ import type { HTMLAttributes } from "vue"
3
+
4
+ const props = defineProps<{
5
+ class?: HTMLAttributes["class"]
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <nav
11
+ aria-label="breadcrumb"
12
+ data-slot="breadcrumb"
13
+ :class="props.class"
14
+ >
15
+ <slot />
16
+ </nav>
17
+ </template>
@@ -0,0 +1,23 @@
1
+ <script lang="ts" setup>
2
+ import type { HTMLAttributes } from "vue"
3
+ import { MoreHorizontal } from "@lucide/vue"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes["class"]
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <span
13
+ data-slot="breadcrumb-ellipsis"
14
+ role="presentation"
15
+ aria-hidden="true"
16
+ :class="cn('flex size-9 items-center justify-center', props.class)"
17
+ >
18
+ <slot>
19
+ <MoreHorizontal class="size-4" />
20
+ </slot>
21
+ <span class="sr-only">More</span>
22
+ </span>
23
+ </template>
@@ -0,0 +1,17 @@
1
+ <script lang="ts" setup>
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes["class"]
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <li
12
+ data-slot="breadcrumb-item"
13
+ :class="cn('inline-flex items-center gap-1.5', props.class)"
14
+ >
15
+ <slot />
16
+ </li>
17
+ </template>
@@ -0,0 +1,21 @@
1
+ <script lang="ts" setup>
2
+ import type { PrimitiveProps } from "reka-ui"
3
+ import type { HTMLAttributes } from "vue"
4
+ import { Primitive } from "reka-ui"
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const props = withDefaults(defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(), {
8
+ as: "a",
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <Primitive
14
+ data-slot="breadcrumb-link"
15
+ :as="as"
16
+ :as-child="asChild"
17
+ :class="cn('hover:text-foreground transition-colors', props.class)"
18
+ >
19
+ <slot />
20
+ </Primitive>
21
+ </template>
@@ -0,0 +1,17 @@
1
+ <script lang="ts" setup>
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes["class"]
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <ol
12
+ data-slot="breadcrumb-list"
13
+ :class="cn('text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5', props.class)"
14
+ >
15
+ <slot />
16
+ </ol>
17
+ </template>
@@ -0,0 +1,20 @@
1
+ <script lang="ts" setup>
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes["class"]
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <span
12
+ data-slot="breadcrumb-page"
13
+ role="link"
14
+ aria-disabled="true"
15
+ aria-current="page"
16
+ :class="cn('text-foreground font-normal', props.class)"
17
+ >
18
+ <slot />
19
+ </span>
20
+ </template>