adminforth 1.0.66 → 1.0.68

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 (63) hide show
  1. package/dist/index.js +20 -12
  2. package/dist/modules/codeInjector.js +12 -2
  3. package/dist/servers/express.js +1 -1
  4. package/dist/spa/index.html +2 -2
  5. package/dist/spa/package-lock.json +1 -189
  6. package/dist/spa/package.json +1 -6
  7. package/dist/spa/spa/index.html +2 -2
  8. package/dist/spa/spa/package-lock.json +4 -4
  9. package/dist/spa/spa/package.json +1 -1
  10. package/dist/spa/spa/public/favicon.png +0 -0
  11. package/dist/spa/spa/src/App.vue +48 -20
  12. package/dist/spa/spa/src/assets/logo.svg +19 -1
  13. package/dist/spa/spa/src/components/ShowTableItem.vue +14 -0
  14. package/dist/spa/spa/src/router/index.ts +12 -5
  15. package/dist/spa/spa/src/stores/core.ts +3 -2
  16. package/dist/spa/spa/src/views/CreateView.vue +1 -1
  17. package/dist/spa/spa/src/views/EditView.vue +1 -1
  18. package/dist/spa/spa/src/views/HomeView.vue +8 -0
  19. package/dist/spa/spa/src/views/ListView.vue +2 -2
  20. package/dist/spa/spa/src/views/ShowView.vue +1 -1
  21. package/dist/spa/spa/vite.config.ts +6 -0
  22. package/dist/spa/src/App.vue +57 -76
  23. package/dist/spa/src/components/AcceptModal.vue +1 -1
  24. package/dist/spa/src/components/CustomDatePicker.vue +3 -3
  25. package/dist/spa/src/components/CustomDateRangePicker.vue +3 -3
  26. package/dist/spa/src/components/Dropdown.vue +4 -13
  27. package/dist/spa/src/components/Filters.vue +22 -55
  28. package/dist/spa/src/components/MenuLink.vue +2 -2
  29. package/dist/spa/src/components/ResourceForm.vue +99 -157
  30. package/dist/spa/src/components/ValueRenderer.vue +1 -11
  31. package/dist/spa/src/router/index.ts +2 -3
  32. package/dist/spa/src/stores/core.ts +33 -22
  33. package/dist/spa/src/utils.ts +3 -5
  34. package/dist/spa/src/views/CreateView.vue +7 -15
  35. package/dist/spa/src/views/EditView.vue +8 -36
  36. package/dist/spa/src/views/HomeView.vue +8 -0
  37. package/dist/spa/src/views/ListView.vue +23 -35
  38. package/dist/spa/src/views/LoginView.vue +1 -1
  39. package/dist/spa/src/views/ResourceParent.vue +1 -1
  40. package/dist/spa/src/views/ShowView.vue +9 -20
  41. package/dist/spa/tailwind.config.js +2 -5
  42. package/documentation/docusaurus.config.ts +2 -2
  43. package/documentation/sidebars.ts +1 -1
  44. package/index.ts +23 -13
  45. package/modules/codeInjector.ts +12 -2
  46. package/package.json +1 -1
  47. package/servers/express.ts +1 -1
  48. package/spa/index.html +2 -2
  49. package/spa/package-lock.json +4 -4
  50. package/spa/package.json +1 -1
  51. package/spa/public/favicon.png +0 -0
  52. package/spa/src/App.vue +48 -20
  53. package/spa/src/assets/logo.svg +19 -1
  54. package/spa/src/router/index.ts +12 -5
  55. package/spa/src/stores/core.ts +3 -2
  56. package/spa/src/views/CreateView.vue +1 -1
  57. package/spa/src/views/EditView.vue +1 -1
  58. package/spa/src/views/ListView.vue +2 -2
  59. package/spa/src/views/ShowView.vue +1 -1
  60. package/spa/vite.config.ts +6 -0
  61. package/types/AdminForthConfig.ts +10 -3
  62. package/dist/spa/src/components/CustomRangePicker.vue +0 -148
  63. package/spa/public/favicon.ico +0 -0
package/dist/index.js CHANGED
@@ -52,6 +52,7 @@ class AdminForth {
52
52
  ;
53
53
  }
54
54
  validateConfig() {
55
+ var _b;
55
56
  if (this.config.rootUser) {
56
57
  if (!this.config.rootUser.username) {
57
58
  throw new Error('rootUser.username is required');
@@ -83,11 +84,17 @@ class AdminForth {
83
84
  if (!this.config.baseUrl) {
84
85
  this.config.baseUrl = '';
85
86
  }
86
- if (!this.config.brandName) {
87
- this.config.brandName = 'AdminForth';
87
+ if (!((_b = this.config) === null || _b === void 0 ? void 0 : _b.customization.brandName)) {
88
+ this.config.customization.brandName = 'AdminForth';
88
89
  }
89
- if (!this.config.datesFormat) {
90
- this.config.datesFormat = 'MMM D, YYYY HH:mm:ss';
90
+ if (this.config.customization.brandLogo) {
91
+ if (!this.config.customization.brandLogo.startsWith('@@/')) {
92
+ errors.push(`Brand logo must start with @@ and be placed in custom directory`);
93
+ }
94
+ // todo check file exist
95
+ }
96
+ if (!this.config.customization.datesFormat) {
97
+ this.config.customization.datesFormat = 'MMM D, YYYY HH:mm:ss';
91
98
  }
92
99
  if (this.config.resources) {
93
100
  this.config.resources.forEach((res) => {
@@ -399,10 +406,10 @@ class AdminForth {
399
406
  const resource = this.config.resources.find((res) => res.resourceId === this.config.auth.resourceId);
400
407
  const usernameColumn = resource.columns.find((col) => col.name === usernameField);
401
408
  return {
402
- brandName: this.config.brandName,
409
+ brandName: this.config.customization.brandName,
403
410
  usernameFieldName: usernameColumn.label,
404
411
  loginBackgroundImage: this.config.auth.loginBackgroundImage,
405
- title: (_e = this.config) === null || _e === void 0 ? void 0 : _e.title,
412
+ title: (_e = this.config.customization) === null || _e === void 0 ? void 0 : _e.title,
406
413
  };
407
414
  }),
408
415
  });
@@ -446,12 +453,13 @@ class AdminForth {
446
453
  })),
447
454
  menu: this.config.menu,
448
455
  config: {
449
- brandName: this.config.brandName,
450
- datesFormat: this.config.datesFormat,
456
+ brandName: this.config.customization.brandName,
457
+ brandLogo: this.config.customization.brandLogo,
458
+ datesFormat: this.config.customization.datesFormat,
451
459
  deleteConfirmation: this.config.deleteConfirmation,
452
460
  auth: this.config.auth,
453
461
  usernameField: this.config.auth.usernameField,
454
- title: (_g = this.config) === null || _g === void 0 ? void 0 : _g.title,
462
+ title: (_g = this.config.customization) === null || _g === void 0 ? void 0 : _g.title,
455
463
  },
456
464
  adminUser,
457
465
  version: ADMINFORTH_VERSION,
@@ -563,9 +571,6 @@ class AdminForth {
563
571
  item[col.name] = targetDataMap[item[col.name]];
564
572
  });
565
573
  })));
566
- data.data.forEach((item) => {
567
- item._label = resource.itemLabel(item);
568
- });
569
574
  for (const hook of getFunctionList((_o = (_m = resource.hooks) === null || _m === void 0 ? void 0 : _m[source]) === null || _o === void 0 ? void 0 : _o.afterDatasourceResponse)) {
570
575
  const resp = yield hook({ resource, response: data.data, adminUser });
571
576
  if (!resp || (!resp.ok && !resp.error)) {
@@ -583,6 +588,9 @@ class AdminForth {
583
588
  }
584
589
  });
585
590
  });
591
+ data.data.forEach((item) => {
592
+ item._label = resource.itemLabel(item);
593
+ });
586
594
  return Object.assign(Object.assign({}, data), { options: resource === null || resource === void 0 ? void 0 : resource.options });
587
595
  }),
588
596
  });
@@ -87,6 +87,7 @@ class CodeInjector {
87
87
  let routerComponents = '';
88
88
  const collectAssetsFromMenu = (menu) => {
89
89
  menu.forEach((item) => {
90
+ var _a, _b, _c, _d;
90
91
  if (item.icon) {
91
92
  icons.push(item.icon);
92
93
  }
@@ -97,6 +98,7 @@ class CodeInjector {
97
98
  path: '${item.path}',
98
99
  name: '${item.path}',
99
100
  component: () => import('${item.component}'),
101
+ meta: { title: '${(_a = item === null || item === void 0 ? void 0 : item.meta) === null || _a === void 0 ? void 0 : _a.title}'}
100
102
  },\n`;
101
103
  }
102
104
  else {
@@ -104,6 +106,7 @@ class CodeInjector {
104
106
  path: '${item.path}',
105
107
  name: '${item.path}',
106
108
  component: ${getComponentNameFromPath(item.component)},
109
+ meta: { title: '${(_b = item === null || item === void 0 ? void 0 : item.meta) === null || _b === void 0 ? void 0 : _b.title}'}
107
110
  },\n`;
108
111
  const componentName = `${getComponentNameFromPath(item.component)}`;
109
112
  routerComponents += `import ${componentName} from '${item.component}';\n`;
@@ -115,6 +118,7 @@ class CodeInjector {
115
118
  path: '${item.path}',
116
119
  name: '${item.path}',
117
120
  component: ${getComponentNameFromPath(item.component)},
121
+ meta: { title: '${(_c = item === null || item === void 0 ? void 0 : item.meta) === null || _c === void 0 ? void 0 : _c.title}'}
118
122
  },\n`;
119
123
  const componentName = `${getComponentNameFromPath(item.component)}`;
120
124
  routerComponents += `import ${componentName} from '${item.component}';\n`;
@@ -123,7 +127,8 @@ class CodeInjector {
123
127
  routes += `{
124
128
  path: '${item.path}',
125
129
  name: '${item.path}',
126
- component: () => import('${item.component}'),
130
+ component: () => import('${item.component}'),}
131
+ meta: { title: '${(_d = item === null || item === void 0 ? void 0 : item.meta) === null || _d === void 0 ? void 0 : _d.title}'
127
132
  },\n`;
128
133
  }
129
134
  }
@@ -214,7 +219,7 @@ class CodeInjector {
214
219
  const componentName = getComponentNameFromPath(filePath);
215
220
  this.allComponentNames[filePath] = componentName;
216
221
  });
217
- console.log('🔧 Injecting code into Vue sources...', this.allComponentNames);
222
+ // console.log('🔧 Injecting code into Vue sources...', this.allComponentNames);
218
223
  let customComponentsImports = '';
219
224
  for (const [targetPath, component] of Object.entries(this.allComponentNames)) {
220
225
  customComponentsImports += `import ${component} from '${targetPath}';\n`;
@@ -258,6 +263,11 @@ class CodeInjector {
258
263
  const routerVuePath = path.join(CodeInjector.SPA_TMP_PATH, 'src', 'router', 'index.ts');
259
264
  let routerVueContent = yield fs.promises.readFile(routerVuePath, 'utf-8');
260
265
  routerVueContent = routerVueContent.replace('/* IMPORTANT:ADMINFORTH ROUTES IMPORTS */', routerComponents);
266
+ // inject title to index.html
267
+ const indexHtmlPath = path.join(CodeInjector.SPA_TMP_PATH, 'index.html');
268
+ let indexHtmlContent = yield fs.promises.readFile(indexHtmlPath, 'utf-8');
269
+ indexHtmlContent = indexHtmlContent.replace('/* IMPORTANT:ADMINFORTH TITLE */', `${this.adminforth.config.customization.title || 'AdminForth'}`);
270
+ yield fs.promises.writeFile(indexHtmlPath, indexHtmlContent);
261
271
  /* generate custom routes */
262
272
  const homepageMenuItem = this.adminforth.config.menu.find((mi) => mi.homepage);
263
273
  let childrenHomePageMenuItem = this.adminforth.config.menu.find((mi) => { var _a; return mi.children && ((_a = mi.children) === null || _a === void 0 ? void 0 : _a.find((mi) => mi.homepage)); });
@@ -126,7 +126,7 @@ class ExpressServer {
126
126
  fileExists = false;
127
127
  }
128
128
  if (!fileExists) {
129
- res.status(500).send(respondNoServer(`${this.adminforth.config.brandName} is still warming up`, 'Please wait a moment...'));
129
+ res.status(500).send(respondNoServer(`${this.adminforth.config.customization.brandName} is still warming up`, 'Please wait a moment...'));
130
130
  return;
131
131
  }
132
132
  res.sendFile(fullPath, {
@@ -16,8 +16,8 @@
16
16
  </script> -->
17
17
 
18
18
  </head>
19
- <body class=" ">
20
- <div id="app" class="min-h-screen bg-html-bg dark:bg-gray-800"></div>
19
+ <body>
20
+ <div id="app" class="min-h-screen dark:bg-gray-800"></div>
21
21
  <script type="module" src="/src/main.ts"></script>
22
22
  </body>
23
23
  </html>
@@ -9,17 +9,12 @@
9
9
  "version": "0.0.0",
10
10
  "dependencies": {
11
11
  "@iconify-prerendered/vue-flowbite": "^0.23.1714023977",
12
- "@unhead/vue": "^1.9.12",
13
- "@vueuse/core": "^10.10.0",
14
12
  "dayjs": "^1.11.11",
15
- "debounce": "^2.1.0",
16
13
  "flowbite": "^2.3.0",
17
14
  "flowbite-datepicker": "^1.2.6",
18
15
  "pinia": "^2.1.7",
19
- "unhead": "^1.9.12",
20
16
  "vue": "^3.4.21",
21
- "vue-router": "^4.3.0",
22
- "vue-slider-component": "^4.1.0-beta.7"
17
+ "vue-router": "^4.3.0"
23
18
  },
24
19
  "devDependencies": {
25
20
  "@rushstack/eslint-patch": "^1.8.0",
@@ -955,11 +950,6 @@
955
950
  "undici-types": "~5.26.4"
956
951
  }
957
952
  },
958
- "node_modules/@types/web-bluetooth": {
959
- "version": "0.0.20",
960
- "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
961
- "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
962
- },
963
953
  "node_modules/@typescript-eslint/eslint-plugin": {
964
954
  "version": "7.9.0",
965
955
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz",
@@ -1151,58 +1141,6 @@
1151
1141
  "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
1152
1142
  "dev": true
1153
1143
  },
1154
- "node_modules/@unhead/dom": {
1155
- "version": "1.9.12",
1156
- "resolved": "https://registry.npmjs.org/@unhead/dom/-/dom-1.9.12.tgz",
1157
- "integrity": "sha512-3MY1TbZmEjGNZapi3wvJW0vWNS2CLKHt7/m57sScDHCNvNBe1mTwrIOhtZFDgAndhml2EVQ68RMa0Vhum/M+cw==",
1158
- "dependencies": {
1159
- "@unhead/schema": "1.9.12",
1160
- "@unhead/shared": "1.9.12"
1161
- },
1162
- "funding": {
1163
- "url": "https://github.com/sponsors/harlan-zw"
1164
- }
1165
- },
1166
- "node_modules/@unhead/schema": {
1167
- "version": "1.9.12",
1168
- "resolved": "https://registry.npmjs.org/@unhead/schema/-/schema-1.9.12.tgz",
1169
- "integrity": "sha512-ue2FKyIZKsuZDpWJBMlBGwMm4s+vFeU3NUWsNt8Z+2JkOUIqO/VG43LxNgY1M595bOS71Gdxk+G9VtzfKJ5uEA==",
1170
- "dependencies": {
1171
- "hookable": "^5.5.3",
1172
- "zhead": "^2.2.4"
1173
- },
1174
- "funding": {
1175
- "url": "https://github.com/sponsors/harlan-zw"
1176
- }
1177
- },
1178
- "node_modules/@unhead/shared": {
1179
- "version": "1.9.12",
1180
- "resolved": "https://registry.npmjs.org/@unhead/shared/-/shared-1.9.12.tgz",
1181
- "integrity": "sha512-72wlLXG3FP3sXUrwd42Uv8jYpHSg4R6IFJcsl+QisRjKM89JnjOFSw1DqWO4IOftW5xOxS4J5v7SQyJ4NJo7Bw==",
1182
- "dependencies": {
1183
- "@unhead/schema": "1.9.12"
1184
- },
1185
- "funding": {
1186
- "url": "https://github.com/sponsors/harlan-zw"
1187
- }
1188
- },
1189
- "node_modules/@unhead/vue": {
1190
- "version": "1.9.12",
1191
- "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-1.9.12.tgz",
1192
- "integrity": "sha512-keE4EuswgzCqVU7zmZprU+ToMvNWc3s8NoLreH5AtJd2u0FgBygD8sxRVyEnZw1KwFYOJ2C7yD2TChSKZioPGQ==",
1193
- "dependencies": {
1194
- "@unhead/schema": "1.9.12",
1195
- "@unhead/shared": "1.9.12",
1196
- "hookable": "^5.5.3",
1197
- "unhead": "1.9.12"
1198
- },
1199
- "funding": {
1200
- "url": "https://github.com/sponsors/harlan-zw"
1201
- },
1202
- "peerDependencies": {
1203
- "vue": ">=2.7 || >=3"
1204
- }
1205
- },
1206
1144
  "node_modules/@vitejs/plugin-vue": {
1207
1145
  "version": "5.0.4",
1208
1146
  "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz",
@@ -1392,89 +1330,6 @@
1392
1330
  "integrity": "sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==",
1393
1331
  "dev": true
1394
1332
  },
1395
- "node_modules/@vueuse/core": {
1396
- "version": "10.10.0",
1397
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.10.0.tgz",
1398
- "integrity": "sha512-vexJ/YXYs2S42B783rI95lMt3GzEwkxzC8Hb0Ndpd8rD+p+Lk/Za4bd797Ym7yq4jXqdSyj3JLChunF/vyYjUw==",
1399
- "dependencies": {
1400
- "@types/web-bluetooth": "^0.0.20",
1401
- "@vueuse/metadata": "10.10.0",
1402
- "@vueuse/shared": "10.10.0",
1403
- "vue-demi": ">=0.14.7"
1404
- },
1405
- "funding": {
1406
- "url": "https://github.com/sponsors/antfu"
1407
- }
1408
- },
1409
- "node_modules/@vueuse/core/node_modules/vue-demi": {
1410
- "version": "0.14.8",
1411
- "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz",
1412
- "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
1413
- "hasInstallScript": true,
1414
- "bin": {
1415
- "vue-demi-fix": "bin/vue-demi-fix.js",
1416
- "vue-demi-switch": "bin/vue-demi-switch.js"
1417
- },
1418
- "engines": {
1419
- "node": ">=12"
1420
- },
1421
- "funding": {
1422
- "url": "https://github.com/sponsors/antfu"
1423
- },
1424
- "peerDependencies": {
1425
- "@vue/composition-api": "^1.0.0-rc.1",
1426
- "vue": "^3.0.0-0 || ^2.6.0"
1427
- },
1428
- "peerDependenciesMeta": {
1429
- "@vue/composition-api": {
1430
- "optional": true
1431
- }
1432
- }
1433
- },
1434
- "node_modules/@vueuse/metadata": {
1435
- "version": "10.10.0",
1436
- "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.10.0.tgz",
1437
- "integrity": "sha512-UNAo2sTCAW5ge6OErPEHb5z7NEAg3XcO9Cj7OK45aZXfLLH1QkexDcZD77HBi5zvEiLOm1An+p/4b5K3Worpug==",
1438
- "funding": {
1439
- "url": "https://github.com/sponsors/antfu"
1440
- }
1441
- },
1442
- "node_modules/@vueuse/shared": {
1443
- "version": "10.10.0",
1444
- "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.10.0.tgz",
1445
- "integrity": "sha512-2aW33Ac0Uk0U+9yo3Ypg9s5KcR42cuehRWl7vnUHadQyFvCktseyxxEPBi1Eiq4D2yBGACOnqLZpx1eMc7g5Og==",
1446
- "dependencies": {
1447
- "vue-demi": ">=0.14.7"
1448
- },
1449
- "funding": {
1450
- "url": "https://github.com/sponsors/antfu"
1451
- }
1452
- },
1453
- "node_modules/@vueuse/shared/node_modules/vue-demi": {
1454
- "version": "0.14.8",
1455
- "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz",
1456
- "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==",
1457
- "hasInstallScript": true,
1458
- "bin": {
1459
- "vue-demi-fix": "bin/vue-demi-fix.js",
1460
- "vue-demi-switch": "bin/vue-demi-switch.js"
1461
- },
1462
- "engines": {
1463
- "node": ">=12"
1464
- },
1465
- "funding": {
1466
- "url": "https://github.com/sponsors/antfu"
1467
- },
1468
- "peerDependencies": {
1469
- "@vue/composition-api": "^1.0.0-rc.1",
1470
- "vue": "^3.0.0-0 || ^2.6.0"
1471
- },
1472
- "peerDependenciesMeta": {
1473
- "@vue/composition-api": {
1474
- "optional": true
1475
- }
1476
- }
1477
- },
1478
1333
  "node_modules/acorn": {
1479
1334
  "version": "8.11.3",
1480
1335
  "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
@@ -1861,17 +1716,6 @@
1861
1716
  "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
1862
1717
  "dev": true
1863
1718
  },
1864
- "node_modules/debounce": {
1865
- "version": "2.1.0",
1866
- "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.1.0.tgz",
1867
- "integrity": "sha512-OkL3+0pPWCqoBc/nhO9u6TIQNTK44fnBnzuVtJAbp13Naxw9R6u21x+8tVTka87AhDZ3htqZ2pSSsZl9fqL2Wg==",
1868
- "engines": {
1869
- "node": ">=18"
1870
- },
1871
- "funding": {
1872
- "url": "https://github.com/sponsors/sindresorhus"
1873
- }
1874
- },
1875
1719
  "node_modules/debug": {
1876
1720
  "version": "4.3.4",
1877
1721
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -2525,11 +2369,6 @@
2525
2369
  "he": "bin/he"
2526
2370
  }
2527
2371
  },
2528
- "node_modules/hookable": {
2529
- "version": "5.5.3",
2530
- "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
2531
- "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
2532
- },
2533
2372
  "node_modules/ignore": {
2534
2373
  "version": "5.3.1",
2535
2374
  "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
@@ -3973,20 +3812,6 @@
3973
3812
  "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
3974
3813
  "dev": true
3975
3814
  },
3976
- "node_modules/unhead": {
3977
- "version": "1.9.12",
3978
- "resolved": "https://registry.npmjs.org/unhead/-/unhead-1.9.12.tgz",
3979
- "integrity": "sha512-s6VxcTV45hy8c/IioKQOonFnAO+kBOSpgDfqEHhnU0YVSQYaRPEp9pzW1qSPf0lx+bg9RKeOQyNNbSGGUP26aQ==",
3980
- "dependencies": {
3981
- "@unhead/dom": "1.9.12",
3982
- "@unhead/schema": "1.9.12",
3983
- "@unhead/shared": "1.9.12",
3984
- "hookable": "^5.5.3"
3985
- },
3986
- "funding": {
3987
- "url": "https://github.com/sponsors/harlan-zw"
3988
- }
3989
- },
3990
3815
  "node_modules/update-browserslist-db": {
3991
3816
  "version": "1.0.16",
3992
3817
  "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
@@ -4145,11 +3970,6 @@
4145
3970
  "vue": "^3.2.0"
4146
3971
  }
4147
3972
  },
4148
- "node_modules/vue-slider-component": {
4149
- "version": "4.1.0-beta.7",
4150
- "resolved": "https://registry.npmjs.org/vue-slider-component/-/vue-slider-component-4.1.0-beta.7.tgz",
4151
- "integrity": "sha512-Qb7K920ZG7PoQswoF6Ias+i3W2rd3k4fpk04JUl82kEUcN86Yg6et7bVSKWt/7VpQe8a5IT3BqCKSCOZ7AJgCA=="
4152
- },
4153
3973
  "node_modules/vue-template-compiler": {
4154
3974
  "version": "2.7.16",
4155
3975
  "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
@@ -4333,14 +4153,6 @@
4333
4153
  "funding": {
4334
4154
  "url": "https://github.com/sponsors/sindresorhus"
4335
4155
  }
4336
- },
4337
- "node_modules/zhead": {
4338
- "version": "2.2.4",
4339
- "resolved": "https://registry.npmjs.org/zhead/-/zhead-2.2.4.tgz",
4340
- "integrity": "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==",
4341
- "funding": {
4342
- "url": "https://github.com/sponsors/harlan-zw"
4343
- }
4344
4156
  }
4345
4157
  }
4346
4158
  }
@@ -13,17 +13,12 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@iconify-prerendered/vue-flowbite": "^0.23.1714023977",
16
- "@unhead/vue": "^1.9.12",
17
- "@vueuse/core": "^10.10.0",
18
16
  "dayjs": "^1.11.11",
19
- "debounce": "^2.1.0",
20
17
  "flowbite": "^2.3.0",
21
18
  "flowbite-datepicker": "^1.2.6",
22
19
  "pinia": "^2.1.7",
23
- "unhead": "^1.9.12",
24
20
  "vue": "^3.4.21",
25
- "vue-router": "^4.3.0",
26
- "vue-slider-component": "^4.1.0-beta.7"
21
+ "vue-router": "^4.3.0"
27
22
  },
28
23
  "devDependencies": {
29
24
  "@rushstack/eslint-patch": "^1.8.0",
@@ -2,9 +2,9 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
- <link rel="icon" href="/favicon.ico">
5
+ <link rel="icon" href="/favicon.png">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Vite App</title>
7
+ <title>/* IMPORTANT:ADMINFORTH TITLE */</title>
8
8
  <!--
9
9
  <script>
10
10
  // On page load or when changing themes, best to add inline in `head` to avoid FOUC
@@ -36,7 +36,7 @@
36
36
  "sass": "^1.77.2",
37
37
  "tailwindcss": "^3.4.3",
38
38
  "typescript": "~5.4.0",
39
- "vite": "^5.2.12",
39
+ "vite": "^5.2.13",
40
40
  "vue-tsc": "^2.0.11"
41
41
  }
42
42
  },
@@ -4033,9 +4033,9 @@
4033
4033
  "dev": true
4034
4034
  },
4035
4035
  "node_modules/vite": {
4036
- "version": "5.2.12",
4037
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz",
4038
- "integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==",
4036
+ "version": "5.2.13",
4037
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz",
4038
+ "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==",
4039
4039
  "dev": true,
4040
4040
  "dependencies": {
4041
4041
  "esbuild": "^0.20.1",
@@ -40,7 +40,7 @@
40
40
  "sass": "^1.77.2",
41
41
  "tailwindcss": "^3.4.3",
42
42
  "typescript": "~5.4.0",
43
- "vite": "^5.2.12",
43
+ "vite": "^5.2.13",
44
44
  "vue-tsc": "^2.0.11"
45
45
  }
46
46
  }
Binary file
@@ -5,7 +5,8 @@
5
5
  <div class="px-3 py-3 lg:px-5 lg:pl-3">
6
6
  <div class="flex items-center justify-between">
7
7
  <div class="flex items-center justify-start rtl:justify-end">
8
- <button data-drawer-target="logo-sidebar" data-drawer-toggle="logo-sidebar" aria-controls="logo-sidebar" type="button" class="inline-flex items-center p-2 text-sm rounded-lg sm:hidden hover:bg-nav-menu-bg-hover focus:outline-none focus:ring-2 focus:ring-nav-menu-devider dark:text-nav-menu-icons dark:hover:bg-nav-menu-bg-hover dark:focus:ring-nav-menu-devider">
8
+ <button @click="sideBarOpen = !sideBarOpen"
9
+ type="button" class="inline-flex items-center p-2 text-sm rounded-lg sm:hidden hover:bg-nav-menu-bg-hover focus:outline-none focus:ring-2 focus:ring-nav-menu-devider dark:text-nav-menu-icons dark:hover:bg-nav-menu-bg-hover dark:focus:ring-nav-menu-devider">
9
10
  <span class="sr-only">Open sidebar</span>
10
11
  <svg class="w-6 h-6" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
11
12
  <path clip-rule="evenodd" fill-rule="evenodd" d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"></path>
@@ -58,15 +59,18 @@
58
59
 
59
60
  v-if="loggedIn && routerIsReady && loginRedirectCheckIsReady"
60
61
 
61
- id="logo-sidebar" class="fixed border-none top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-full bg-nav-menu-bg border-r border- sm:translate-x-0 dark:bg-gray-800 dark:border-gray-700" aria-label="Sidebar">
62
+ id="logo-sidebar" class="fixed border-none top-0 left-0 z-50 w-64 h-screen transition-transform bg-nav-menu-bg border-r border- sm:translate-x-0 dark:bg-gray-800 dark:border-gray-700"
63
+ :class="{ '-translate-x-full': !sideBarOpen, 'transform-none': sideBarOpen }"
64
+ aria-label="Sidebar"
65
+ >
62
66
  <div class="h-full px-3 pb-4 overflow-y-auto bg-nav-menu-bg dark:bg-gray-800">
63
67
 
64
68
  <div class="flex ms-2 md:me-24 m-4 ">
65
- <img src="https://flowbite.com/docs/images/logo.svg" class="h-8 me-3" alt="FlowBite Logo" />
66
- <span class="self-center text-header-text-size font-semibold sm:text-header-text-size whitespace-nowrap dark:text-header-text text-header-logo-color">
67
- {{ coreStore.config?.brandName }}
68
- </span>
69
- </div>
69
+ <img :src="loadFile(coreStore.config?.brandLogo || '@/assets/logo.svg')" alt="logo" class="w-8 h-8 mr-2" />
70
+ <span class="self-center text-header-text-size font-semibold sm:text-header-text-size whitespace-nowrap dark:text-header-text text-header-logo-color">
71
+ {{ coreStore.config?.brandName }}
72
+ </span>
73
+ </div>
70
74
  <ul class="space-y-2 font-medium">
71
75
  <template v-for="(item, i) in coreStore.menu" :key="`menu-${i}`">
72
76
  <div v-if="item.type === 'divider'" class="border-t border-nav-menu-devider dark:border-gray-700"></div>
@@ -101,7 +105,8 @@
101
105
  </ul>
102
106
  </div>
103
107
  </aside>
104
-
108
+
109
+
105
110
  <div class="p-4 sm:ml-64 dark:bg-gray-800" v-if="loggedIn && routerIsReady && loginRedirectCheckIsReady">
106
111
  <div class="p-0 dark:border-gray-700 mt-14">
107
112
  <RouterView/>
@@ -119,6 +124,11 @@
119
124
  </div>
120
125
  <AcceptModal />
121
126
 
127
+ <div v-if="sideBarOpen"
128
+ @click="sideBarOpen = false"
129
+
130
+ drawer-backdrop="" class="bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-30"></div>
131
+
122
132
  </template>
123
133
 
124
134
  <style scoped>
@@ -141,14 +151,42 @@ import { createHead } from 'unhead'
141
151
  const coreStore = useCoreStore();
142
152
 
143
153
 
144
- createHead()
154
+ const splitAtLast = (str: string, separator: string) => {
155
+ const index = str.lastIndexOf(separator);
156
+ return [str.slice(0, index), str.slice(index + 1)];
157
+ }
158
+
159
+ const loadFile = (file: string) => {
160
+ let path;
161
+ let baseUrl = '';
162
+ if (file.startsWith('@/')) {
163
+ path = file.replace('@/', '');
164
+ baseUrl = new URL(`./${path}`, import.meta.url).href;
165
+ } else if (file.startsWith('@@/')) {
166
+ path = file.replace('@@/', '');
167
+ baseUrl = new URL(`./custom/${path}`, import.meta.url).href;
168
+ } else {
169
+ baseUrl = new URL(`./${file}`, import.meta.url).href;
170
+ }
171
+ return baseUrl;
172
+ }
145
173
 
146
174
 
175
+ createHead()
147
176
 
148
177
 
178
+ const sideBarOpen = ref(false);
179
+
149
180
 
150
181
 
151
182
  const route = useRoute();
183
+ watch(route, () => {
184
+ title.value = `${coreStore.config?.title || coreStore.config?.brandName || 'Adminforth'} | ${ Object.values(route.params)[0] || route.meta.title || ' '}`;
185
+ useHead({
186
+ title: title.value,
187
+ })
188
+ });
189
+
152
190
  const router = useRouter();
153
191
  const title = ref('');
154
192
  //create a ref to store the opened menu items with ts type;
@@ -197,17 +235,7 @@ onMounted(async () => {
197
235
  }, 100);
198
236
  await coreStore.fetchMenuAndResource();
199
237
  loginRedirectCheckIsReady.value = true;
200
- title.value = coreStore.config?.title || 'AdminForth';
201
- useHead({
202
- title: title.value,
203
- link: [
204
- {
205
- rel: 'icon',
206
- href: coreStore.config.favicon || '/favicon.ico',
207
- },
208
- ],
209
-
210
- })
238
+
211
239
  coreStore.menu.forEach((item, i) => {
212
240
  if (item.open) {
213
241
  opened.value.push(i);
@@ -1 +1,19 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_1_8)">
3
+ <path d="M8.034 6.006V13H6.097V12.194C5.59433 12.8007 4.86633 13.104 3.913 13.104C3.25433 13.104 2.65633 12.9567 2.119 12.662C1.59033 12.3673 1.17433 11.947 0.871 11.401C0.567667 10.855 0.416 10.2223 0.416 9.503C0.416 8.78367 0.567667 8.151 0.871 7.605C1.17433 7.059 1.59033 6.63867 2.119 6.344C2.65633 6.04933 3.25433 5.902 3.913 5.902C4.80567 5.902 5.50333 6.18367 6.006 6.747V6.006H8.034ZM4.264 11.44C4.77533 11.44 5.2 11.2667 5.538 10.92C5.876 10.5647 6.045 10.0923 6.045 9.503C6.045 8.91367 5.876 8.44567 5.538 8.099C5.2 7.74367 4.77533 7.566 4.264 7.566C3.744 7.566 3.315 7.74367 2.977 8.099C2.639 8.44567 2.47 8.91367 2.47 9.503C2.47 10.0923 2.639 10.5647 2.977 10.92C3.315 11.2667 3.744 11.44 4.264 11.44Z" fill="url(#paint0_linear_1_8)"/>
4
+ <path d="M13.317 5.538C12.589 5.538 12.0387 5.69833 11.666 6.019C11.2933 6.331 11.107 6.80333 11.107 7.436V7.995H14.851V9.685H11.107V13H9.001V7.449C9.001 6.279 9.365 5.369 10.093 4.719C10.8297 4.069 11.8567 3.744 13.174 3.744C13.694 3.744 14.1837 3.80033 14.643 3.913C15.1023 4.017 15.501 4.173 15.839 4.381L15.189 6.045C14.669 5.707 14.045 5.538 13.317 5.538Z" fill="url(#paint1_linear_1_8)"/>
5
+ </g>
6
+ <defs>
7
+ <linearGradient id="paint0_linear_1_8" x1="1.5" y1="6.93333" x2="7.31883" y2="11.8926" gradientUnits="userSpaceOnUse">
8
+ <stop stop-color="#656E7A"/>
9
+ <stop offset="1" stop-color="#99A6B8"/>
10
+ </linearGradient>
11
+ <linearGradient id="paint1_linear_1_8" x1="12.5" y1="3.73333" x2="9.68642" y2="12.7016" gradientUnits="userSpaceOnUse">
12
+ <stop stop-color="#48C5FF"/>
13
+ <stop offset="1" stop-color="#A1E1FF"/>
14
+ </linearGradient>
15
+ <clipPath id="clip0_1_8">
16
+ <rect width="16" height="16" fill="white"/>
17
+ </clipPath>
18
+ </defs>
19
+ </svg>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <td class="px-6 py-4 whitespace-nowrap">
3
+ {{ column.label }}
4
+ </td>
5
+ <td class="px-6 py-4 whitespace-nowrap whitespace-pre-wrap">
6
+ <ValueRenderer :column="column" :row="row" />
7
+ </td>
8
+ </template>
9
+
10
+ <script setup>
11
+ import ValueRenderer from '@/components/ValueRenderer.vue';
12
+
13
+ defineProps(['column', 'row']);
14
+ </script>