create-nexgen 1.0.4

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 (240) hide show
  1. package/package.json +26 -0
  2. package/src/index.js +108 -0
  3. package/template/.dockerignore +14 -0
  4. package/template/.env +58 -0
  5. package/template/.env.example +59 -0
  6. package/template/.prettierignore +5 -0
  7. package/template/.prettierrc +8 -0
  8. package/template/README.md +447 -0
  9. package/template/drizzle.config.ts +29 -0
  10. package/template/eslint.config.js +52 -0
  11. package/template/gitignore-stub +24 -0
  12. package/template/package.json +96 -0
  13. package/template/public/assets/AuthLayout-CbswhpjJ.js +1 -0
  14. package/template/public/assets/Button-_7aQ7gHL.js +1 -0
  15. package/template/public/assets/Input-CLNJXmKc.css +1 -0
  16. package/template/public/assets/Input-z8GI8Aqo.js +1 -0
  17. package/template/public/assets/InputPasswordToggle-BxlzVGp3.js +1 -0
  18. package/template/public/assets/InputPasswordToggle-C77FI9Eg.css +1 -0
  19. package/template/public/assets/Layout-DotR1sQC.js +1 -0
  20. package/template/public/assets/Refresh-BdqsPPBC.js +1 -0
  21. package/template/public/assets/admin-ui-CU34rLdN.js +1 -0
  22. package/template/public/assets/bootstrap-icons-BeopsB42.woff +0 -0
  23. package/template/public/assets/bootstrap-icons-mSm7cUeB.woff2 +0 -0
  24. package/template/public/assets/dashboard-CwybEyLc.js +1 -0
  25. package/template/public/assets/dashboard-Dc4d-Pi7.css +1 -0
  26. package/template/public/assets/forgetPassword-CKEJaXsq.js +1 -0
  27. package/template/public/assets/index-Bleyx5dm.js +64 -0
  28. package/template/public/assets/index-DUw8E6Yg.css +1 -0
  29. package/template/public/assets/login-DC7PTlQF.js +1 -0
  30. package/template/public/assets/realtime-test-BPQdrFym.css +1 -0
  31. package/template/public/assets/realtime-test-tQZ0rBEJ.js +1 -0
  32. package/template/public/assets/register-3O7Qs28C.js +1 -0
  33. package/template/public/assets/resetPassword-A5AzMWKs.js +1 -0
  34. package/template/public/assets/verifyEmail-DDBEQHOv.js +1 -0
  35. package/template/public/index.html +17 -0
  36. package/template/src/database/migrations/mysql/0000_init.sql +73 -0
  37. package/template/src/database/migrations/mysql/meta/0000_snapshot.json +484 -0
  38. package/template/src/database/migrations/mysql/meta/_journal.json +13 -0
  39. package/template/src/database/schema.ts +4 -0
  40. package/template/src/env.ts +107 -0
  41. package/template/src/framework/cache/cache.ts +81 -0
  42. package/template/src/framework/database/connection.ts +168 -0
  43. package/template/src/framework/database/optional-db-drivers.d.ts +9 -0
  44. package/template/src/framework/database/paginate.ts +200 -0
  45. package/template/src/framework/database/schema.ts +26 -0
  46. package/template/src/framework/database/seed.ts +33 -0
  47. package/template/src/framework/events/dispatcher.ts +57 -0
  48. package/template/src/framework/facade.ts +27 -0
  49. package/template/src/framework/http/app.ts +61 -0
  50. package/template/src/framework/http/cors.ts +19 -0
  51. package/template/src/framework/http/logger.ts +85 -0
  52. package/template/src/framework/http/openapi.ts +34 -0
  53. package/template/src/framework/http/ratelimiter.ts +13 -0
  54. package/template/src/framework/http/router.ts +76 -0
  55. package/template/src/framework/http/static.ts +33 -0
  56. package/template/src/framework/http/validation.ts +24 -0
  57. package/template/src/framework/kernel.ts +40 -0
  58. package/template/src/framework/maker-cli/src/index.mjs +51 -0
  59. package/template/src/framework/maker-cli/src/levels/level-1/env-db.mjs +57 -0
  60. package/template/src/framework/maker-cli/src/levels/level-1/file-ops.mjs +30 -0
  61. package/template/src/framework/maker-cli/src/levels/level-1/flags.mjs +16 -0
  62. package/template/src/framework/maker-cli/src/levels/level-1/help.mjs +24 -0
  63. package/template/src/framework/maker-cli/src/levels/level-1/naming.mjs +13 -0
  64. package/template/src/framework/maker-cli/src/levels/level-1/process.mjs +47 -0
  65. package/template/src/framework/maker-cli/src/levels/level-2/db/core.mjs +299 -0
  66. package/template/src/framework/maker-cli/src/levels/level-2/db/index.mjs +177 -0
  67. package/template/src/framework/maker-cli/src/levels/level-2/deploy/core.mjs +635 -0
  68. package/template/src/framework/maker-cli/src/levels/level-2/deploy/index.mjs +145 -0
  69. package/template/src/framework/maker-cli/src/levels/level-2/module/core.mjs +707 -0
  70. package/template/src/framework/maker-cli/src/levels/level-2/module/index.mjs +116 -0
  71. package/template/src/framework/maker-cli/src/levels/level-2/runtime/build-frontend.mjs +16 -0
  72. package/template/src/framework/maker-cli/src/levels/level-2/runtime/core.mjs +311 -0
  73. package/template/src/framework/maker-cli/src/levels/level-2/runtime/index.mjs +71 -0
  74. package/template/src/framework/maker-cli/stubs/controller/openapi.ts.stub +55 -0
  75. package/template/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +56 -0
  76. package/template/src/framework/maker-cli/stubs/controller/plain.ts.stub +57 -0
  77. package/template/src/framework/maker-cli/stubs/controller/schema.plain.ts.stub +13 -0
  78. package/template/src/framework/maker-cli/stubs/controller/schema.ts.stub +32 -0
  79. package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +49 -0
  80. package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +53 -0
  81. package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +49 -0
  82. package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +53 -0
  83. package/template/src/framework/maker-cli/stubs/deploy/README.stub +55 -0
  84. package/template/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +29 -0
  85. package/template/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +29 -0
  86. package/template/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +29 -0
  87. package/template/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +73 -0
  88. package/template/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +73 -0
  89. package/template/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +72 -0
  90. package/template/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +15 -0
  91. package/template/src/framework/maker-cli/stubs/deploy/server/README.stub +77 -0
  92. package/template/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +118 -0
  93. package/template/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +131 -0
  94. package/template/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +129 -0
  95. package/template/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +10 -0
  96. package/template/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +24 -0
  97. package/template/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +24 -0
  98. package/template/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +15 -0
  99. package/template/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +12 -0
  100. package/template/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +13 -0
  101. package/template/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +6 -0
  102. package/template/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +53 -0
  103. package/template/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +69 -0
  104. package/template/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +24 -0
  105. package/template/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +20 -0
  106. package/template/src/framework/maker-cli/stubs/example/console.ts.stub +33 -0
  107. package/template/src/framework/maker-cli/stubs/example/controller.ts.stub +503 -0
  108. package/template/src/framework/maker-cli/stubs/example/job.ts.stub +74 -0
  109. package/template/src/framework/maker-cli/stubs/example/route.api.ts.stub +206 -0
  110. package/template/src/framework/maker-cli/stubs/example/schema.ts.stub +41 -0
  111. package/template/src/framework/maker-cli/stubs/job/name.ts.stub +24 -0
  112. package/template/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +8 -0
  113. package/template/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +8 -0
  114. package/template/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +8 -0
  115. package/template/src/framework/maker-cli/stubs/notification/NotificationBell.vue.stub +218 -0
  116. package/template/src/framework/maker-cli/stubs/notification/controller.ts.stub +85 -0
  117. package/template/src/framework/maker-cli/stubs/notification/index.vue.stub +211 -0
  118. package/template/src/framework/maker-cli/stubs/notification/job.ts.stub +12 -0
  119. package/template/src/framework/maker-cli/stubs/notification/route.api.ts.stub +49 -0
  120. package/template/src/framework/maker-cli/stubs/notification/schema.ts.stub +25 -0
  121. package/template/src/framework/maker-cli/stubs/route/api.ts.stub +79 -0
  122. package/template/src/framework/maker-cli/stubs/route/plain.ts.stub +10 -0
  123. package/template/src/framework/maker-cli/stubs/schedule/name.ts.stub +35 -0
  124. package/template/src/framework/maker-cli/stubs/seeder/name.ts.stub +17 -0
  125. package/template/src/framework/modules/discover.ts +54 -0
  126. package/template/src/framework/modules/routes.ts +26 -0
  127. package/template/src/framework/notification/index.ts +109 -0
  128. package/template/src/framework/queue/clear.ts +20 -0
  129. package/template/src/framework/queue/queue.ts +213 -0
  130. package/template/src/framework/queue/ui.ts +104 -0
  131. package/template/src/framework/queue/worker.ts +33 -0
  132. package/template/src/framework/realtime/broadcast.ts +27 -0
  133. package/template/src/framework/realtime/index.ts +1 -0
  134. package/template/src/framework/realtime/socket-cookie.ts +65 -0
  135. package/template/src/framework/realtime/socket.ts +132 -0
  136. package/template/src/framework/realtime/types.ts +6 -0
  137. package/template/src/framework/realtime/ui.ts +16 -0
  138. package/template/src/framework/redis/client.ts +126 -0
  139. package/template/src/framework/scheduler/lock.ts +124 -0
  140. package/template/src/framework/scheduler/run.ts +26 -0
  141. package/template/src/framework/scheduler/scheduler.ts +82 -0
  142. package/template/src/framework/server.ts +147 -0
  143. package/template/src/framework/session/session.ts +116 -0
  144. package/template/src/framework/storage/storage.ts +743 -0
  145. package/template/src/framework/support/cookie.ts +78 -0
  146. package/template/src/framework/support/jwt.ts +45 -0
  147. package/template/src/framework/support/lifecycle.ts +35 -0
  148. package/template/src/framework/support/logger.ts +102 -0
  149. package/template/src/framework/support/mail.ts +43 -0
  150. package/template/src/framework/support/password.ts +23 -0
  151. package/template/src/framework/support/url.ts +25 -0
  152. package/template/src/middlewares/auth-middleware.ts +98 -0
  153. package/template/src/middlewares/role-middleware.ts +24 -0
  154. package/template/src/modules/auth/controllers/auth.controller.ts +445 -0
  155. package/template/src/modules/auth/controllers/auth.helpers.ts +110 -0
  156. package/template/src/modules/auth/controllers/auth.schema.ts +102 -0
  157. package/template/src/modules/auth/controllers/role.controller.ts +25 -0
  158. package/template/src/modules/auth/database/models/notifications.ts +22 -0
  159. package/template/src/modules/auth/database/models/role.ts +14 -0
  160. package/template/src/modules/auth/database/models/user.ts +46 -0
  161. package/template/src/modules/auth/database/seeders/role.ts +19 -0
  162. package/template/src/modules/auth/database/seeders/user.ts +33 -0
  163. package/template/src/modules/auth/jobs/forgetpass.ts +18 -0
  164. package/template/src/modules/auth/jobs/registeruser.ts +31 -0
  165. package/template/src/modules/auth/jobs/verifyemail.ts +18 -0
  166. package/template/src/modules/auth/routes/api.ts +151 -0
  167. package/template/src/modules/auth/routes/role.ts +39 -0
  168. package/template/src/modules/welcome/controllers/welcome.controller.ts +14 -0
  169. package/template/src/modules/welcome/controllers/welcome.schema.ts +6 -0
  170. package/template/src/modules/welcome/database/models/welcome.ts +6 -0
  171. package/template/src/modules/welcome/routes/api.ts +20 -0
  172. package/template/src/resources/index.html +16 -0
  173. package/template/src/resources/src/App.vue +5 -0
  174. package/template/src/resources/src/assets/css/styles.css +14934 -0
  175. package/template/src/resources/src/assets/css/styles.css.map +1 -0
  176. package/template/src/resources/src/assets/images/favicon/favicon.ico +0 -0
  177. package/template/src/resources/src/assets/images/favicon/favicon1.ico +0 -0
  178. package/template/src/resources/src/assets/images/logo-1.png +0 -0
  179. package/template/src/resources/src/assets/images/logo-dark-sm.png +0 -0
  180. package/template/src/resources/src/assets/images/logo-dark.png +0 -0
  181. package/template/src/resources/src/assets/images/logo-dark1.png +0 -0
  182. package/template/src/resources/src/assets/images/logo-sm.png +0 -0
  183. package/template/src/resources/src/assets/images/logo1.png +0 -0
  184. package/template/src/resources/src/assets/images/logo2.png +0 -0
  185. package/template/src/resources/src/assets/scss/custom.css +217 -0
  186. package/template/src/resources/src/assets/scss/custom.css.map +1 -0
  187. package/template/src/resources/src/assets/scss/custom.scss +1100 -0
  188. package/template/src/resources/src/components/Button.vue +35 -0
  189. package/template/src/resources/src/components/Checkbox.vue +29 -0
  190. package/template/src/resources/src/components/FloatButton.vue +36 -0
  191. package/template/src/resources/src/components/Href.vue +32 -0
  192. package/template/src/resources/src/components/Input.vue +227 -0
  193. package/template/src/resources/src/components/InputGroup.vue +153 -0
  194. package/template/src/resources/src/components/InputPasswordToggle.vue +226 -0
  195. package/template/src/resources/src/components/Modal.vue +102 -0
  196. package/template/src/resources/src/components/Pagebar.vue +28 -0
  197. package/template/src/resources/src/components/Refresh.vue +26 -0
  198. package/template/src/resources/src/components/Select.vue +390 -0
  199. package/template/src/resources/src/components/Spinner.vue +42 -0
  200. package/template/src/resources/src/components/Switch.vue +65 -0
  201. package/template/src/resources/src/components/TextArea.vue +121 -0
  202. package/template/src/resources/src/components/Toast.vue +56 -0
  203. package/template/src/resources/src/components/datatable/DataTableSkeleton.vue +99 -0
  204. package/template/src/resources/src/components/datatable/Pagination.vue +161 -0
  205. package/template/src/resources/src/components/datatable/SelectOpption.vue +54 -0
  206. package/template/src/resources/src/components/datatable/index.vue +237 -0
  207. package/template/src/resources/src/composables/useAuth.ts +52 -0
  208. package/template/src/resources/src/composables/useBrowserDetect.ts +5 -0
  209. package/template/src/resources/src/composables/useDialog.ts +5 -0
  210. package/template/src/resources/src/composables/useGum.ts +3 -0
  211. package/template/src/resources/src/composables/usePulse.ts +5 -0
  212. package/template/src/resources/src/env.d.ts +20 -0
  213. package/template/src/resources/src/helpers/nformatter.ts +10 -0
  214. package/template/src/resources/src/helpers/utils.ts +68 -0
  215. package/template/src/resources/src/layouts/AuthLayout.vue +20 -0
  216. package/template/src/resources/src/layouts/Layout/Footer.vue +23 -0
  217. package/template/src/resources/src/layouts/Layout/Header.vue +90 -0
  218. package/template/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
  219. package/template/src/resources/src/layouts/Layout/index.vue +76 -0
  220. package/template/src/resources/src/main.ts +27 -0
  221. package/template/src/resources/src/pages/auth/forgetPassword.vue +76 -0
  222. package/template/src/resources/src/pages/auth/login.vue +93 -0
  223. package/template/src/resources/src/pages/auth/register.vue +130 -0
  224. package/template/src/resources/src/pages/auth/resetPassword.vue +119 -0
  225. package/template/src/resources/src/pages/auth/verifyEmail.vue +60 -0
  226. package/template/src/resources/src/pages/dashboard/index.vue +76 -0
  227. package/template/src/resources/src/plugins/axios.ts +33 -0
  228. package/template/src/resources/src/plugins/browserDetect.ts +55 -0
  229. package/template/src/resources/src/plugins/dialog.ts +167 -0
  230. package/template/src/resources/src/plugins/gum.ts +343 -0
  231. package/template/src/resources/src/plugins/pulse.ts +141 -0
  232. package/template/src/resources/src/plugins/routeProgress.ts +87 -0
  233. package/template/src/resources/src/router/index.ts +85 -0
  234. package/template/src/resources/src/stores/admin-ui.ts +148 -0
  235. package/template/src/resources/src/stores/auth.ts +151 -0
  236. package/template/src/resources/tsconfig.json +19 -0
  237. package/template/src/resources/vite.config.ts +43 -0
  238. package/template/src/storage/logs/app.log +20179 -0
  239. package/template/src/storage/logs/fatal.log +727 -0
  240. package/template/tsconfig.json +20 -0
@@ -0,0 +1,99 @@
1
+ <template>
2
+ <div class="card h-100 border">
3
+ <div class="card-header bg-white border-bottom-0 pb-0 px-2 px-sm-3">
4
+ <div class="row align-items-center">
5
+ <div class="col-12 col-sm-6 col-lg-3 col-xl-3 mb-2 mb-lg-0 d-flex">
6
+ <div class="py-2 rounded-1 border bg-custom ps-3 me-2"></div>
7
+ <div class="form-control py-2 bg-custom"></div>
8
+ </div>
9
+ <div class="col-12 col-sm-6 col-lg-4 col-xl-5 mb-2 mb-lg-0">
10
+ <slot name="extra-option"></slot>
11
+ </div>
12
+ <div class="col-12 col-lg-5 col-xl-4">
13
+ <div class="row gx-1">
14
+ <div class="col-2 col-sm-4 col-md-6 col-lg-2 text-start text-lg-end">
15
+ <span class="form-control py-2 bg-custom"></span>
16
+ </div>
17
+ <div class="mb-2 mb-sm-0 text-start col-6 col-sm-6 col-md-4 col-lg-7">
18
+ <span class="form-control py-2 bg-custom"></span>
19
+ </div>
20
+ <div class="col-4 col-sm-2 col-md-2 col-lg-3 text-end">
21
+ <span class="bg-custom form-control py-2"></span>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ <div class="card-body py-3 px-2 px-sm-3">
28
+ <div class="table-responsive rounded-1">
29
+ <table class="table table-bordered table-striped table-sm align-middle m-0">
30
+ <thead>
31
+ <tr>
32
+ <th v-for="dt in colCount" :key="`h-${dt}`" class="bg-custom py-2"></th>
33
+ </tr>
34
+ </thead>
35
+ <tbody>
36
+ <tr v-for="r in rowCount" :key="`r-${r}`">
37
+ <td v-for="c in colCount" :key="`c-${r}-${c}`" class="bg-custom py-2"></td>
38
+ </tr>
39
+ </tbody>
40
+ </table>
41
+ </div>
42
+ </div>
43
+ <div class="card-footer bg-white border-top-0 pt-0 px-2 px-sm-3">
44
+ <div class="row align-items-center">
45
+ <div class="col-12 col-md-5 mb-2 mb-md-0"></div>
46
+ <div class="col-12 col-md-7 text-center text-md-end">
47
+ <span class="form-control bg-custom py-2"></span>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </template>
53
+
54
+ <script setup lang="ts">
55
+ import { computed, useAttrs } from "vue";
56
+
57
+ defineOptions({ inheritAttrs: false });
58
+
59
+ const $attrs = useAttrs();
60
+ const colCount = computed(() => Number($attrs.col ?? 1));
61
+ const rowCount = computed(() => Number($attrs.row ?? 1));
62
+ </script>
63
+
64
+ <style lang="scss" scoped>
65
+ table,
66
+ tr,
67
+ th,
68
+ td {
69
+ border-color: #cccccc;
70
+ animation: anim 3s infinite;
71
+ }
72
+
73
+ .bg-custom {
74
+ background-color: #efefef;
75
+ animation: anim 3s infinite;
76
+ }
77
+
78
+ @keyframes anim {
79
+ 0% {
80
+ background-color: #efefef;
81
+ }
82
+
83
+ 25% {
84
+ background-color: #f8f8f8;
85
+ }
86
+
87
+ 50% {
88
+ background-color: #efefef;
89
+ }
90
+
91
+ 75% {
92
+ background-color: #f8f8f8;
93
+ }
94
+
95
+ 100% {
96
+ background-color: #efefef;
97
+ }
98
+ }
99
+ </style>
@@ -0,0 +1,161 @@
1
+ <template>
2
+ <div class="row">
3
+ <div class="col-12 col-md-6 mb-3 mb-md-0">
4
+ <div class="py-2 text-black-50 text-center text-md-start">
5
+ Showing {{ page.from }} to {{ page.to }} of {{ nFormatter(page.total) }} entries
6
+ </div>
7
+ </div>
8
+ <div class="col-12 col-md-6">
9
+ <nav class="datatable-pagination" aria-label="Page navigation">
10
+ <ul class="pagination justify-content-center justify-content-md-end">
11
+ <!-- First -->
12
+ <li :class="['page-item', { disabled: noPreviousPage }]">
13
+ <button
14
+ type="button"
15
+ class="page-link"
16
+ :aria-disabled="noPreviousPage ? 'true' : 'false'"
17
+ :tabindex="noPreviousPage ? -1 : 0"
18
+ @click.prevent="!noPreviousPage && loadPage(1)">
19
+ <i class="bi bi-chevron-double-left"></i>
20
+ </button>
21
+ </li>
22
+
23
+ <!-- Prev -->
24
+ <li :class="['page-item', { disabled: noPreviousPage }]">
25
+ <button
26
+ type="button"
27
+ class="page-link"
28
+ :aria-disabled="noPreviousPage ? 'true' : 'false'"
29
+ :tabindex="noPreviousPage ? -1 : 0"
30
+ @click.prevent="!noPreviousPage && loadPage(props.data.current_page - 1)">
31
+ <i class="bi bi-chevron-left"></i>
32
+ </button>
33
+ </li>
34
+
35
+ <li class="page-item">
36
+ <div class="input-group input-group-sm">
37
+ <Input
38
+ v-model="page.page"
39
+ type="text"
40
+ category="number"
41
+ topclass="m-0"
42
+ class="text-center"
43
+ style="width: 100px"
44
+ @keyup.enter="loadPage(page.page)" />
45
+ </div>
46
+ </li>
47
+
48
+ <li class="page-item lastpage">
49
+ <span class="page-link text-nowrap"> of {{ nFormatter(props.data.last_page) }} </span>
50
+ </li>
51
+
52
+ <!-- Next -->
53
+ <li :class="['page-item', { disabled: noNextPage }]">
54
+ <button
55
+ type="button"
56
+ class="page-link"
57
+ :aria-disabled="noNextPage ? 'true' : 'false'"
58
+ :tabindex="noNextPage ? -1 : 0"
59
+ @click.prevent="!noNextPage && loadPage(props.data.current_page + 1)">
60
+ <i class="bi bi-chevron-right"></i>
61
+ </button>
62
+ </li>
63
+
64
+ <!-- Last -->
65
+ <li :class="['page-item', { disabled: noNextPage }]">
66
+ <button
67
+ type="button"
68
+ class="page-link"
69
+ :aria-disabled="noNextPage ? 'true' : 'false'"
70
+ :tabindex="noNextPage ? -1 : 0"
71
+ @click.prevent="!noNextPage && loadPage(props.data.last_page)">
72
+ <i class="bi bi-chevron-double-right"></i>
73
+ </button>
74
+ </li>
75
+ </ul>
76
+ </nav>
77
+ </div>
78
+ </div>
79
+ </template>
80
+
81
+ <script setup lang="ts">
82
+ import { reactive, computed, watchEffect } from "vue";
83
+ import { useGum } from "@/composables/useGum";
84
+ import { formatCompactNumber } from "@/helpers/nformatter";
85
+ import Input from "../Input.vue";
86
+
87
+ interface PaginationData {
88
+ current_page: number;
89
+ last_page: number;
90
+ per_page: number;
91
+ total: number;
92
+ path: string;
93
+ }
94
+
95
+ interface PaginationProps {
96
+ data: PaginationData;
97
+ selectedoption?: string | number;
98
+ search?: string;
99
+ }
100
+
101
+ const props = withDefaults(defineProps<PaginationProps>(), {
102
+ search: ""
103
+ });
104
+ const gum = useGum();
105
+
106
+ const page = reactive({ page: 1, from: 0, to: 0, total: 0 });
107
+
108
+ const noPreviousPage = computed(() => props.data.current_page - 1 <= 0);
109
+ const noNextPage = computed(() => props.data.current_page + 1 > props.data.last_page);
110
+
111
+ const loadPage = (pageNo: string | number) => {
112
+ let p = parseInt(String(pageNo), 10);
113
+
114
+ // fallback if NaN
115
+ if (isNaN(p)) p = props.data.current_page;
116
+
117
+ const last = Number(props.data.last_page) || 1;
118
+
119
+ // clamp between 1 and last
120
+ if (p < 1) p = 1;
121
+ if (p > last) p = last;
122
+
123
+ return gum.get(props.data.path, {
124
+ query: { page: p, size: props.selectedoption, search: props.search },
125
+ preserveState: true,
126
+ preserveScroll: true
127
+ });
128
+ };
129
+
130
+ const nFormatter = formatCompactNumber;
131
+
132
+ watchEffect(() => {
133
+ // "Showing {$from} to {$to} of {$total} entries"
134
+ page.page = props.data.current_page;
135
+ page.from = (props.data.current_page - 1) * props.data.per_page + 1;
136
+ page.to = Math.min(props.data.current_page * props.data.per_page, props.data.total);
137
+ page.total = props.data.total;
138
+ });
139
+ </script>
140
+
141
+ <style lang="scss" scoped>
142
+ ul.pagination {
143
+ margin: 0;
144
+
145
+ :deep(.page-item.disabled .page-link),
146
+ :deep(.page-link:disabled),
147
+ :deep(.page-link[aria-disabled="true"]) {
148
+ pointer-events: none;
149
+ cursor: not-allowed;
150
+ opacity: 0.5;
151
+ }
152
+
153
+ .page-link {
154
+ border-radius: 5px !important;
155
+ margin-left: 0;
156
+ border-color: #cdcdcd !important;
157
+ color: inherit;
158
+ box-shadow: none;
159
+ }
160
+ }
161
+ </style>
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <div
3
+ class="d-flex align-items-center justify-content-center justify-content-md-start mb-2 mb-md-0"
4
+ :class="{ 'd-none': !props.isOptions }">
5
+ Show
6
+ <select
7
+ v-model="selectedoption"
8
+ class="form-select shadow-none w-auto mx-2"
9
+ @change="selectOption">
10
+ <option v-for="(val, i) in props.option" :key="i" :value="val">{{ val }}</option>
11
+ </select>
12
+ entries
13
+ </div>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import { ref } from "vue";
18
+ import { useGum } from "@/composables/useGum";
19
+
20
+ interface DataPage {
21
+ path: string;
22
+ current_page: number;
23
+ }
24
+
25
+ interface SelectOptionProps {
26
+ data: DataPage;
27
+ search?: string;
28
+ isOptions?: boolean;
29
+ option?: Array<string | number>;
30
+ selectedoption?: string | number;
31
+ }
32
+
33
+ const props = withDefaults(defineProps<SelectOptionProps>(), {
34
+ search: "",
35
+ isOptions: true,
36
+ option: () => []
37
+ });
38
+ const gum = useGum();
39
+
40
+ // select option and pass SelectOption component
41
+ const selectedoption = ref<string | number | undefined>(props.selectedoption);
42
+ const selectOption = (e: Event) => {
43
+ const target = e.target as HTMLSelectElement;
44
+ selectedoption.value = target.value;
45
+
46
+ return gum.get(props.data.path, {
47
+ query: { page: props.data.current_page, size: selectedoption.value, search: props.search },
48
+ preserveState: true,
49
+ preserveScroll: true
50
+ });
51
+ };
52
+ </script>
53
+
54
+ <style lang="scss" scoped></style>
@@ -0,0 +1,237 @@
1
+ <template>
2
+ <div class="card border h-100">
3
+ <div
4
+ class="card-header"
5
+ :class="{ 'd-none': !(props.removable || props.searchable || props.optionable) }">
6
+ <div class="row align-items-center gx-1">
7
+ <div class="col-12 col-md-3">
8
+ <SelectOption
9
+ :is-options="props.optionable"
10
+ :option="props.option"
11
+ :data="dataForOption"
12
+ :selectedoption="selectedoption"
13
+ :search="searchdata" />
14
+ </div>
15
+ <div class="col-12 col-md-9">
16
+ <slot name="extra-tools"></slot>
17
+ <div class="d-flex align-items-center justify-content-center justify-content-md-end">
18
+ <div
19
+ v-if="checked.checkcolumn.length > 0"
20
+ class="me-1"
21
+ :class="{ 'd-none': !props.removable }">
22
+ <Button type="button" class="btn btn-outline-danger" @click.prevent="remove">
23
+ <i class="bi bi-trash"></i>
24
+ </Button>
25
+ </div>
26
+ <div class="d-flex align-items-center" :class="{ 'd-none': !props.searchable }">
27
+ <Button
28
+ class="btn btn-outline-secondary rounded-0 rounded-start"
29
+ type="button"
30
+ @click="searchMe">
31
+ <i class="bi bi-search"></i>
32
+ </Button>
33
+ <Input
34
+ v-model="searchdata"
35
+ type="text"
36
+ class="form-control w-auto rounded-0 rounded-end"
37
+ topclass="mb-0"
38
+ placeholder="Search..."
39
+ @keyup.enter="searchMe"
40
+ @keyup.delete="searchMe" />
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ <div class="card-body">
47
+ <slot name="extra"></slot>
48
+ <div class="table-responsive">
49
+ <table
50
+ class="table table-bordered table-striped border-custom table-sm align-middle m-0 datatable no-shrink-table">
51
+ <slot name="customhead"></slot>
52
+ <thead :class="{ 'd-none': slots.customhead }">
53
+ <tr>
54
+ <th
55
+ class="align-middle"
56
+ :class="{ 'd-none': !props.removable || !props.data.current_page }">
57
+ <Checkbox
58
+ v-model="checked.check"
59
+ topclass="ms-2"
60
+ :value="checked.check"
61
+ :disabled="props.disabled"
62
+ @click="checkAll" />
63
+ </th>
64
+ <th class="text-center align-middle" :class="{ 'd-none': !props.countable }">#</th>
65
+ <slot name="thead"></slot>
66
+ </tr>
67
+ </thead>
68
+
69
+ <slot name="custombody"></slot>
70
+ <tbody :class="{ 'd-none': slots.custombody }">
71
+ <tr v-for="(dt, i) in tableRows" :key="`${dt.id}-${i}`">
72
+ <td
73
+ class="align-middle"
74
+ :class="{ 'd-none': !props.removable || !props.data.current_page }">
75
+ <Checkbox
76
+ v-model="checked.checkcolumn"
77
+ topclass="ms-2"
78
+ :value="dt.id"
79
+ :disabled="props.disabled"
80
+ @change="updateChecked" />
81
+ </td>
82
+ <td class="text-center align-middle" :class="{ 'd-none': !props.countable }">
83
+ {{
84
+ props.data.current_page
85
+ ? props.data.per_page * (props.data.current_page - 1) + (i + 1)
86
+ : i + 1
87
+ }}
88
+ </td>
89
+ <slot name="tbody" :td="dt"></slot>
90
+ </tr>
91
+ </tbody>
92
+ </table>
93
+ </div>
94
+ </div>
95
+ <div class="card-footer" :class="{ 'd-none': props.data.total <= props.data.data?.length }">
96
+ <Pagination :data="props.data" :selectedoption="selectedoption" :search="searchdata" />
97
+ </div>
98
+ </div>
99
+ </template>
100
+
101
+ <script setup lang="ts">
102
+ import { computed, reactive, ref, useSlots, watchEffect } from "vue";
103
+ import { debounce } from "lodash-es";
104
+ import { useGum } from "@/composables/useGum";
105
+
106
+ import Checkbox from "../Checkbox.vue";
107
+ import Button from "../Button.vue";
108
+ import SelectOption from "./SelectOpption.vue";
109
+ import Pagination from "./Pagination.vue";
110
+
111
+ import Input from "../Input.vue";
112
+
113
+ interface DataRow {
114
+ id: string | number;
115
+ [key: string]: unknown;
116
+ }
117
+ interface PaginatedData {
118
+ data: DataRow[];
119
+ current_page: number;
120
+ last_page: number;
121
+ per_page: number;
122
+ total: number;
123
+ path: string;
124
+ }
125
+ interface DataPage {
126
+ path: string;
127
+ current_page: number;
128
+ }
129
+ interface DataTableProps {
130
+ data: PaginatedData;
131
+ search?: string;
132
+ loop?: DataRow[] | false;
133
+ option?: Array<string | number>;
134
+ removable?: boolean;
135
+ countable?: boolean;
136
+ searchable?: boolean;
137
+ optionable?: boolean;
138
+ disabled?: boolean;
139
+ }
140
+
141
+ const props = withDefaults(defineProps<DataTableProps>(), {
142
+ search: "",
143
+ option: () => [],
144
+ removable: true,
145
+ countable: true,
146
+ searchable: true,
147
+ optionable: true,
148
+ disabled: false
149
+ });
150
+ const gum = useGum();
151
+
152
+ const slots = useSlots();
153
+
154
+ const emit = defineEmits<{
155
+ (event: "remove", value: Array<string | number>): void;
156
+ }>();
157
+
158
+ // checkbox select
159
+ let checked = reactive<{ check: boolean; checkcolumn: Array<string | number> }>({
160
+ check: false,
161
+ checkcolumn: []
162
+ });
163
+ const checkAll = () => {
164
+ if (!checked.check) {
165
+ props.data.data.forEach((dt: DataRow) => {
166
+ if (!checked.checkcolumn.includes(dt.id)) {
167
+ checked.checkcolumn.push(dt.id);
168
+ }
169
+ });
170
+ } else {
171
+ checked.checkcolumn = [];
172
+ }
173
+ };
174
+ const updateChecked = () =>
175
+ checked.checkcolumn.length == props.data.data.length
176
+ ? (checked.check = true)
177
+ : (checked.check = false);
178
+
179
+ // remove from parent
180
+ const remove = () => {
181
+ emit("remove", checked.checkcolumn);
182
+ checked.check = false;
183
+ };
184
+
185
+ // for change data size show
186
+ const selectedoption = ref<string | number | undefined>(undefined);
187
+ const dataForOption = computed<DataPage>(() => ({
188
+ path: props.data.path,
189
+ current_page: props.data.current_page
190
+ }));
191
+ const tableRows = computed<DataRow[]>(() => (props.loop ? props.loop : props.data.data));
192
+
193
+ // search data
194
+ const searchdata = ref(props.search || "");
195
+ const searchMe = debounce(() => {
196
+ const isSearching = !!searchdata.value && searchdata.value.trim() !== "";
197
+ gum.get(props.data.path, {
198
+ query: {
199
+ page: isSearching ? 1 : props.data.current_page, // Go to page 1 if searching
200
+ size: selectedoption.value,
201
+ search: searchdata.value
202
+ },
203
+ preserveState: true,
204
+ preserveScroll: true
205
+ });
206
+ }, 500);
207
+
208
+ // watch instantce
209
+ watchEffect(() => {
210
+ selectedoption.value = props.option.find((x) => Number(x) === Number(props.data.per_page));
211
+ });
212
+ </script>
213
+
214
+ <style lang="scss" scoped>
215
+ .border-custom {
216
+ border-color: #cccccc !important;
217
+ }
218
+
219
+ .no-shrink-table th,
220
+ .no-shrink-table td {
221
+ white-space: nowrap;
222
+ }
223
+
224
+ /* By default (large screens and up) do not force a min-width:
225
+ allow table to size normally so no horizontal scrollbar on large screens */
226
+ @media (min-width: 992px) {
227
+ .no-shrink-table {
228
+ min-width: 0;
229
+ }
230
+ }
231
+
232
+ @media (max-width: 991.98px) {
233
+ .no-shrink-table {
234
+ min-width: 1000px;
235
+ }
236
+ }
237
+ </style>
@@ -0,0 +1,52 @@
1
+ import { computed, readonly, ref, type Ref } from "vue";
2
+
3
+ type UnknownRecord = Record<string, unknown>;
4
+
5
+ export type RoleLike = {
6
+ id?: string | number;
7
+ name?: string;
8
+ title?: string;
9
+ slug?: string;
10
+ } & UnknownRecord;
11
+
12
+ export type AuthUser = UnknownRecord & {
13
+ id?: string | number;
14
+ name?: string;
15
+ role?: RoleLike | null;
16
+ roles?: RoleLike[] | null;
17
+ };
18
+
19
+ const userRef: Ref<AuthUser | null> = ref(null);
20
+
21
+ export function setUser(user: AuthUser | null) {
22
+ userRef.value = user;
23
+ }
24
+
25
+ export function clearUser() {
26
+ userRef.value = null;
27
+ }
28
+
29
+ export function useAuth() {
30
+ return {
31
+ user: readonly(userRef),
32
+ isAuthenticated: computed(() => !!userRef.value),
33
+ setUser,
34
+ clearUser
35
+ };
36
+ }
37
+
38
+ export const authUser = computed<AuthUser>(() => userRef.value ?? {});
39
+
40
+ export function hasRole(...wanted: string[]): boolean {
41
+ const subject = userRef.value;
42
+ if (!subject) return false;
43
+
44
+ const current = (subject.roles ?? (subject.role ? [subject.role] : []))
45
+ .map((item) => (item.name || item.title || item.slug || "").toLowerCase().trim())
46
+ .filter(Boolean);
47
+
48
+ if (!wanted.length) return current.length > 0;
49
+
50
+ const expected = wanted.map((item) => item.toLowerCase().trim()).filter(Boolean);
51
+ return current.some((item) => expected.includes(item));
52
+ }
@@ -0,0 +1,5 @@
1
+ import { browserDetect, type BrowserDetectResult } from "@/plugins/browserDetect";
2
+
3
+ export default function useBrowserDetect(): BrowserDetectResult {
4
+ return browserDetect;
5
+ }
@@ -0,0 +1,5 @@
1
+ import { dialog } from "@/plugins/dialog";
2
+
3
+ export function useDialog() {
4
+ return dialog;
5
+ }
@@ -0,0 +1,3 @@
1
+ import { useGum, useGumForm, useGumRemember } from "@/plugins/gum";
2
+
3
+ export { useGum, useGumForm, useGumRemember };
@@ -0,0 +1,5 @@
1
+ import { pulse } from "@/plugins/pulse";
2
+
3
+ export function usePulse() {
4
+ return pulse;
5
+ }
@@ -0,0 +1,20 @@
1
+ declare module "*.vue" {
2
+ import type { DefineComponent } from "vue";
3
+ const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
4
+ export default component;
5
+ }
6
+
7
+ declare module "bootstrap/js/dist/modal.js" {
8
+ export default class Modal {
9
+ constructor(element: Element, options?: { backdrop?: boolean | "static"; keyboard?: boolean });
10
+ show(): void;
11
+ hide(): void;
12
+ dispose(): void;
13
+ }
14
+ }
15
+
16
+ declare module "vue-select" {
17
+ import type { DefineComponent } from "vue";
18
+ const VueSelect: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
19
+ export default VueSelect;
20
+ }
@@ -0,0 +1,10 @@
1
+ const compactFormatter = new Intl.NumberFormat("en", {
2
+ notation: "compact",
3
+ maximumFractionDigits: 1
4
+ });
5
+
6
+ export function formatCompactNumber(value: number): string | number {
7
+ if (!Number.isFinite(value)) return String(value);
8
+ if (Math.abs(value) < 1000) return value;
9
+ return compactFormatter.format(value).replace(/\s/g, "");
10
+ }