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,68 @@
1
+ import axios from "axios";
2
+
3
+ declare const route: (name: string, params?: Record<string, unknown>) => string;
4
+
5
+ export function inArray<T>(needle: T, haystack: T[], strict = false): boolean {
6
+ if (!Array.isArray(haystack)) {
7
+ throw new TypeError("haystack must be an array");
8
+ }
9
+
10
+ if (strict) {
11
+ return haystack.includes(needle);
12
+ }
13
+
14
+ for (const value of haystack) {
15
+ if (value == needle) {
16
+ return true;
17
+ }
18
+
19
+ if (
20
+ typeof value === "number" &&
21
+ typeof needle === "number" &&
22
+ Number.isNaN(value) &&
23
+ Number.isNaN(needle)
24
+ ) {
25
+ return true;
26
+ }
27
+ }
28
+
29
+ return false;
30
+ }
31
+
32
+ export function empty(v: unknown): boolean {
33
+ if (v == null) return true;
34
+ if (typeof v === "boolean") return v === false;
35
+ if (typeof v === "number") return v === 0 || Number.isNaN(v);
36
+ if (typeof v === "bigint") return v === 0n;
37
+ if (typeof v === "string") return v === "" || v === "0";
38
+ if (Array.isArray(v)) return v.length === 0;
39
+ if (v instanceof Map || v instanceof Set) return v.size === 0;
40
+ if (typeof v === "object") return Object.keys(v).length === 0;
41
+
42
+ return false;
43
+ }
44
+
45
+ export async function downloadFile(url: string, fileName: string): Promise<void> {
46
+ try {
47
+ const isDirectUrl =
48
+ url.startsWith("/") || url.startsWith("http://") || url.startsWith("https://");
49
+ const targetUrl = isDirectUrl ? url : route(url, { file_name: fileName });
50
+ const res = await axios.get(targetUrl, { responseType: "blob" });
51
+ if (res.data) {
52
+ const objectUrl = window.URL.createObjectURL(new Blob([res.data]));
53
+ const link = document.createElement("a");
54
+ link.href = objectUrl;
55
+ link.setAttribute("download", fileName);
56
+ document.body.appendChild(link);
57
+ link.click();
58
+ link.remove();
59
+ window.URL.revokeObjectURL(objectUrl);
60
+ }
61
+ } catch (e) {
62
+ console.error("Export failed:", e);
63
+ }
64
+ }
65
+
66
+ export async function downloadExcel(url: string, fileName: string): Promise<void> {
67
+ await downloadFile(url, fileName);
68
+ }
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <router-view />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { onBeforeUnmount, onMounted } from "vue";
7
+ import { useAdminUiStore } from "@/stores/admin-ui";
8
+
9
+ const ui = useAdminUiStore();
10
+
11
+ onMounted(() => {
12
+ ui.initTheme();
13
+ });
14
+
15
+ onBeforeUnmount(() => {
16
+ ui.cleanupTheme();
17
+ });
18
+ </script>
19
+
20
+ <style scoped></style>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <!-- footer start -->
3
+ <footer
4
+ class="d-flex flex-column flex-sm-row row-gap-2 align-items-center justify-content-center justify-content-sm-between py-3 fst-italic">
5
+ <div class="text-secondary">
6
+ © nexgen {{ startYear }} - {{ currentYear }} ❤️ created by
7
+ <a href="#" target="_blank" class="text-decoration-none">niYam</a>
8
+ </div>
9
+ <div class="d-block">
10
+ <a href="#" target="_blank" class="text-decoration-none me-2">About</a>
11
+ <a href="#" target="_blank" class="text-decoration-none me-2">Support</a>
12
+ <a href="#" target="_blank" class="text-decoration-none me-2">Contact Us</a>
13
+ </div>
14
+ </footer>
15
+ <!-- footer end -->
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ const startYear: number = 2026;
20
+ const currentYear: number = new Date().getFullYear();
21
+ </script>
22
+
23
+ <style scoped></style>
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <header :class="{ scrolled: isScrolled }">
3
+ <nav class="navbar bg-transparent p-0">
4
+ <div class="container-fluid p-0 row-gap-2 column-gap-1">
5
+ <button
6
+ id="off-canvas"
7
+ type="button"
8
+ class="nav-btn order-0"
9
+ title="Toggle Button"
10
+ @click="props.onToggleSidebar">
11
+ <i class="bi bi-layout-text-sidebar-reverse"></i>
12
+ </button>
13
+ <div id="pagebar" class="card card-body nav-card order-5 order-sm-1"></div>
14
+ <!-- <button id="refresh" type="button" class="nav-btn order-3 order-sm-2" aria-label="button">
15
+ <i class="bi bi-arrow-repeat"></i>
16
+ </button> -->
17
+ <div class="btn-group order-4 order-sm-3">
18
+ <button
19
+ type="button"
20
+ class="nav-btn w-100"
21
+ data-bs-toggle="dropdown"
22
+ data-bs-display="static"
23
+ aria-expanded="false"
24
+ aria-label="button">
25
+ <i class="bi bi-person-circle"></i>
26
+ </button>
27
+ <ul class="dropdown-menu dropdown-menu-end">
28
+ <li>
29
+ <a class="dropdown-item" href="#">
30
+ <div class="d-flex align-items-center">
31
+ <div class="flex-shrink-0 me-3">
32
+ <i class="bi bi-person-circle fs-1"></i>
33
+ </div>
34
+ <div class="flex-grow-1 text-capitalize">
35
+ <h6 class="mb-0">{{ authUser?.name }}</h6>
36
+ <small class="text-muted">{{ authUser.role?.name }}</small>
37
+ </div>
38
+ </div>
39
+ </a>
40
+ </li>
41
+ <li>
42
+ <div class="dropdown-divider my-1"></div>
43
+ </li>
44
+ <li>
45
+ <a class="dropdown-item" href="#">
46
+ <i class="bi bi-person-check me-3"></i><span>My Profile</span>
47
+ </a>
48
+ </li>
49
+ <li>
50
+ <button type="button" class="dropdown-item" @click="props.onLogout">
51
+ <i class="bi bi-power me-3"></i><span>Log Out</span>
52
+ </button>
53
+ </li>
54
+ </ul>
55
+ </div>
56
+ <button
57
+ id="theme-switch"
58
+ type="button"
59
+ class="nav-btn order-1 order-sm-4"
60
+ aria-label="button"
61
+ @click="props.onToggleTheme">
62
+ <i :class="themeIconClass"></i>
63
+ </button>
64
+ </div>
65
+ </nav>
66
+ </header>
67
+ </template>
68
+
69
+ <script setup lang="ts">
70
+ import { computed } from "vue";
71
+ import { authUser } from "@/composables/useAuth";
72
+
73
+ interface HeaderProps {
74
+ isScrolled: boolean;
75
+ themeMode: "light" | "dark" | "auto";
76
+ onLogout: () => void | Promise<void>;
77
+ onToggleSidebar: () => void;
78
+ onToggleTheme: () => void;
79
+ }
80
+
81
+ const props = defineProps<HeaderProps>();
82
+
83
+ const themeIconClass = computed(() => {
84
+ if (props.themeMode === "light") return "bi bi-brightness-high-fill";
85
+ if (props.themeMode === "dark") return "bi bi-moon-stars";
86
+ return "bi bi-circle-half";
87
+ });
88
+ </script>
89
+
90
+ <style lang="scss" scoped></style>
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <!-- sidebar start -->
3
+ <div class="sidebar">
4
+ <a
5
+ href="#"
6
+ role="button"
7
+ class="sidebar-toggle card card-body rounded-circle position-absolute top-0 end-0 d-xl-none"
8
+ title="sidebar-toggle"
9
+ @click.prevent="props.onToggleSidebar">
10
+ <i class="bi bi-chevron-left fw-bold"></i>
11
+ </a>
12
+
13
+ <div class="app-brand">
14
+ <a href="#" class="fw-semibold fs-2" aria-label="logo">
15
+ <h2 class="m-0 fw-semibold">NEXGEN</h2>
16
+ </a>
17
+ </div>
18
+ <div id="accordion-sidebar" class="accordion accordion-flush">
19
+ <ul class="list-group px-3">
20
+ <li class="list-group-item" :class="{ active: isActive('/') }">
21
+ <router-link to="/">
22
+ <div class="menu-icon">
23
+ <i class="bi bi-house"></i>
24
+ </div>
25
+ <span>Dashboard</span>
26
+ </router-link>
27
+ </li>
28
+ <li class="split-label">
29
+ <span class="text-uppercase">setup</span>
30
+ </li>
31
+ <li class="list-group-item accordion-item">
32
+ <a
33
+ href="#"
34
+ class="accordion-button collapsed"
35
+ type="button"
36
+ data-bs-toggle="collapse"
37
+ data-bs-target="#flush-collapseOne"
38
+ aria-expanded="false"
39
+ aria-controls="flush-collapseOne">
40
+ <div class="menu-icon">
41
+ <i class="bi bi-shield-check"></i>
42
+ </div>
43
+ <span>Content</span>
44
+ </a>
45
+ <ul
46
+ id="flush-collapseOne"
47
+ class="list-group accordion-collapse collapse"
48
+ data-bs-parent="#accordion-sidebar">
49
+ <li class="list-group-item">
50
+ <a href="#">Posts</a>
51
+ </li>
52
+ <li class="list-group-item">
53
+ <a href="#">Pages</a>
54
+ </li>
55
+ <li class="list-group-item accordion-item">
56
+ <a
57
+ href="#"
58
+ class="accordion-button collapsed"
59
+ type="button"
60
+ data-bs-toggle="collapse"
61
+ data-bs-target="#flush-collapseTwo"
62
+ aria-expanded="false"
63
+ aria-controls="flush-collapseTwo">
64
+ <span>Media</span>
65
+ </a>
66
+ <ul id="flush-collapseTwo" class="list-group accordion-collapse collapse">
67
+ <li class="list-group-item">
68
+ <a href="#">Image</a>
69
+ </li>
70
+ <li class="list-group-item active">
71
+ <a href="#">Audio</a>
72
+ </li>
73
+ <li class="list-group-item accordion-item">
74
+ <a
75
+ href="#"
76
+ class="accordion-button collapsed"
77
+ type="button"
78
+ data-bs-toggle="collapse"
79
+ data-bs-target="#flush-collapseThree"
80
+ aria-expanded="false"
81
+ aria-controls="flush-collapseThree">
82
+ <span>Settings</span>
83
+ </a>
84
+ <ul id="flush-collapseThree" class="list-group accordion-collapse collapse">
85
+ <li class="list-group-item">
86
+ <a href="#">Users</a>
87
+ </li>
88
+ <li class="list-group-item">
89
+ <a href="#">Roles</a>
90
+ </li>
91
+ </ul>
92
+ </li>
93
+ </ul>
94
+ </li>
95
+ </ul>
96
+ </li>
97
+ <li class="list-group-item">
98
+ <a href="#">
99
+ <div class="menu-icon">
100
+ <i class="bi bi-chat"></i>
101
+ </div>
102
+ <span>Comments</span>
103
+ </a>
104
+ </li>
105
+ <li class="list-group-item">
106
+ <a href="#">
107
+ <div class="menu-icon">
108
+ <i class="bi bi-gear"></i>
109
+ </div>
110
+ <span>Tools</span>
111
+ </a>
112
+ </li>
113
+ </ul>
114
+ </div>
115
+ </div>
116
+ <!-- sidebar end -->
117
+ </template>
118
+
119
+ <script setup lang="ts">
120
+ import { onBeforeUnmount, onMounted } from "vue";
121
+ import { useRoute } from "vue-router";
122
+ import { useAdminUiStore } from "@/stores/admin-ui";
123
+
124
+ const props = defineProps<{ onToggleSidebar: () => void; }>();
125
+
126
+ const ui = useAdminUiStore();
127
+ const route = useRoute();
128
+
129
+ function isActive(path: string) {
130
+ return route.path === path;
131
+ }
132
+
133
+ onMounted(() => ui.initSidebarCollapsePersistence());
134
+ onBeforeUnmount(() => ui.cleanupSidebarCollapsePersistence());
135
+ </script>
136
+
137
+ <style lang="scss" scoped></style>
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <Sidebar :class="{ tgl: sidebarOpen }" :on-toggle-sidebar="ui.toggleSidebar" />
3
+ <!-- main start -->
4
+ <div class="main" :class="{ tgl: sidebarOpen, 'no-transition': disableTransition }">
5
+ <div class="content-wrapper container-xxl px-0">
6
+ <Header
7
+ :is-scrolled="headerScrolled"
8
+ :theme-mode="themeMode"
9
+ :on-logout="logout"
10
+ :on-toggle-sidebar="ui.toggleSidebar"
11
+ :on-toggle-theme="ui.cycleTheme" />
12
+ <!-- content start -->
13
+ <div class="content">
14
+ <router-view />
15
+ </div>
16
+ <!-- content end -->
17
+ <Footer />
18
+ </div>
19
+ </div>
20
+ <!-- main end -->
21
+ <div class="backdrop" :class="{ 'off-canvas': sidebarOpen }" @click="ui.toggleSidebar"></div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { onBeforeUnmount, onMounted, ref } from "vue";
26
+ import { useRouter } from "vue-router";
27
+ import Footer from "./Footer.vue";
28
+ import Header from "./Header.vue";
29
+ import Sidebar from "./Sidebar.vue";
30
+ import { storeToRefs } from "pinia";
31
+ import { useAdminUiStore } from "@/stores/admin-ui";
32
+ import { useAuthStore } from "@/stores/auth";
33
+
34
+ const ui = useAdminUiStore();
35
+ const auth = useAuthStore();
36
+ const router = useRouter();
37
+ const { themeMode, sidebarOpen } = storeToRefs(ui);
38
+ const headerScrolled = ref(false);
39
+ const disableTransition = ref(true);
40
+
41
+ async function logout() {
42
+ await auth.logout();
43
+ await router.push("/login");
44
+ }
45
+
46
+ function onScroll() {
47
+ const y = window.scrollY;
48
+ if (y > 20) {
49
+ headerScrolled.value = true;
50
+ } else if (y < 5) {
51
+ headerScrolled.value = false;
52
+ }
53
+ }
54
+
55
+ onMounted(() => {
56
+ ui.initTheme();
57
+
58
+ window.addEventListener("scroll", onScroll, { passive: true });
59
+ onScroll();
60
+
61
+ // Force reflow then enable transitions on next frame
62
+ void document.body.offsetHeight;
63
+ requestAnimationFrame(() => {
64
+ requestAnimationFrame(() => {
65
+ disableTransition.value = false;
66
+ });
67
+ });
68
+ });
69
+
70
+ onBeforeUnmount(() => {
71
+ window.removeEventListener("scroll", onScroll);
72
+ ui.cleanupTheme();
73
+ });
74
+ </script>
75
+
76
+ <style scoped></style>
@@ -0,0 +1,27 @@
1
+ import "@/plugins/axios";
2
+ import { createApp } from "vue";
3
+ import { createPinia } from "pinia";
4
+ import { createHead } from "@vueuse/head";
5
+ import { DialogPlugin } from "@/plugins/dialog";
6
+ import { PulsePlugin } from "@/plugins/pulse";
7
+ import { GumPlugin } from "@/plugins/gum";
8
+
9
+ import App from "./App.vue";
10
+ import router from "./router";
11
+
12
+ import "bootstrap/dist/css/bootstrap.min.css";
13
+ import "bootstrap-icons/font/bootstrap-icons.css";
14
+ import "@/assets/scss/custom.scss";
15
+ import "bootstrap/dist/js/bootstrap.bundle.min.js";
16
+
17
+ const app = createApp(App);
18
+ const pinia = createPinia();
19
+ const head = createHead({ titleTemplate: (title) => (title ? `${title} | Nexgen` : "Nexgen") });
20
+
21
+ app.use(pinia);
22
+ app.use(router);
23
+ app.use(head);
24
+ app.use(DialogPlugin);
25
+ app.use(GumPlugin);
26
+ app.use(PulsePlugin);
27
+ app.mount("#app");
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <div class="container position-absolute start-50 top-50 translate-middle">
3
+ <div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
4
+ <div class="card card-body border-0">
5
+ <div class="d-block mb-2">
6
+ <h3 class="m-0 text-uppercase text-center fw-semibold">nexgen</h3>
7
+ </div>
8
+ <h4 class="text-center">Forget Password</h4>
9
+ <p
10
+ v-if="message"
11
+ class="text-center alert py-1 mt-2"
12
+ :class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
13
+ {{ message }}
14
+ </p>
15
+ <form id="formAuthentication" @submit.prevent="onSubmit">
16
+ <div class="mb-4">
17
+ <Input
18
+ id="email"
19
+ v-model="form.email"
20
+ type="email"
21
+ label="email"
22
+ placeholder="Enter your email..."
23
+ :err="false"
24
+ focus
25
+ must />
26
+ </div>
27
+ <Button
28
+ type="submit"
29
+ label="Send Reset Link"
30
+ class="btn btn-primary d-grid w-100"
31
+ icon="bi bi-send ms-2"
32
+ :disabled="auth.processing" />
33
+ </form>
34
+ <div class="text-center mt-2">
35
+ <router-link to="/login">
36
+ <i class="bx bx-chevron-left scaleX-n1-rtl me-1"></i>
37
+ <span>Back to login</span>
38
+ </router-link>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </template>
44
+
45
+ <script setup lang="ts">
46
+ import { reactive, ref } from "vue";
47
+ import { useHead } from "@vueuse/head";
48
+ import Input from "../../components/Input.vue";
49
+ import Button from "../../components/Button.vue";
50
+ import { useAuthStore } from "@/stores/auth";
51
+
52
+ useHead({ title: "Forget Password" });
53
+
54
+ const auth = useAuthStore();
55
+
56
+ interface ForgotPasswordForm {
57
+ email: string;
58
+ }
59
+
60
+ const form = reactive<ForgotPasswordForm>({ email: "" });
61
+ const message = ref("");
62
+ const isError = ref(false);
63
+
64
+ const onSubmit = async () => {
65
+ message.value = "";
66
+ isError.value = false;
67
+ try {
68
+ message.value = await auth.forgotPassword({ email: form.email.trim() });
69
+ } catch (error: unknown) {
70
+ isError.value = true;
71
+ message.value = error instanceof Error ? error.message : "Failed to process request";
72
+ }
73
+ };
74
+ </script>
75
+
76
+ <style lang="scss" scoped></style>
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <div class="container position-absolute start-50 top-50 translate-middle">
3
+ <div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
4
+ <div class="card card-body border-0">
5
+ <div class="d-block mb-2">
6
+ <h3 class="m-0 text-uppercase text-center fw-semibold">nexgen</h3>
7
+ </div>
8
+ <p v-if="errorMessage" class="text-center alert alert-danger text-danger py-1 mt-2">
9
+ {{ errorMessage }}
10
+ </p>
11
+ <form @submit.prevent="onSubmit">
12
+ <div class="mb-4">
13
+ <Input
14
+ id="email"
15
+ v-model="form.email"
16
+ type="email"
17
+ label="email"
18
+ placeholder="Enter your email..."
19
+ :err="false"
20
+ focus
21
+ must />
22
+ </div>
23
+ <div class="mb-4">
24
+ <input-password-toggle
25
+ id="password"
26
+ v-model="form.password"
27
+ label="password"
28
+ placeholder="Enter your password..."
29
+ :err="false"
30
+ must />
31
+ </div>
32
+ <div class="mb-4 d-flex align-items-center justify-content-between">
33
+ <Checkbox id="remember-me" v-model="form.remember" label="Remember me" />
34
+ <router-link to="/forget-password" class="text-decoration-none mb-1">Forget Password?</router-link>
35
+ </div>
36
+ <button type="submit" class="btn btn-primary w-100" :disabled="auth.processing">
37
+ <span>Login</span>
38
+ <i class="bi bi-box-arrow-in-right ms-2"></i>
39
+ </button>
40
+ <div class="text-center mt-3">
41
+ <span class="text-muted">Don't have an account?</span>
42
+ <router-link to="/register" class="ms-1 text-decoration-none">Register</router-link>
43
+ </div>
44
+ </form>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </template>
49
+
50
+ <script setup lang="ts">
51
+ import { reactive, ref } from "vue";
52
+ import { useRouter } from "vue-router";
53
+ import { useHead } from "@vueuse/head";
54
+ import { useAuthStore } from "@/stores/auth";
55
+
56
+ import Input from "@/components/Input.vue";
57
+ import InputPasswordToggle from "@/components/InputPasswordToggle.vue";
58
+ import Checkbox from "@/components/Checkbox.vue";
59
+
60
+ useHead({ title: "Login" });
61
+
62
+ const router = useRouter();
63
+ const auth = useAuthStore();
64
+ const errorMessage = ref("");
65
+
66
+ interface LoginForm {
67
+ email: string;
68
+ password: string;
69
+ remember: boolean;
70
+ }
71
+
72
+ const form = reactive<LoginForm>({
73
+ email: "",
74
+ password: "",
75
+ remember: false
76
+ });
77
+
78
+ const onSubmit = async () => {
79
+ errorMessage.value = "";
80
+ try {
81
+ await auth.login({
82
+ email: form.email.trim(),
83
+ password: form.password,
84
+ remember: form.remember
85
+ });
86
+ await router.push("/");
87
+ } catch (error: unknown) {
88
+ errorMessage.value = error instanceof Error ? error.message : "Unable to login right now";
89
+ }
90
+ };
91
+ </script>
92
+
93
+ <style lang="scss" scoped></style>