diff --git a/eslint.config.js b/eslint.config.js
index 5a53d6f..5afe7aa 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -3,6 +3,7 @@ import pluginVitest from '@vitest/eslint-plugin';
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting';
import vueTsEslintConfig from '@vue/eslint-config-typescript';
import oxlint from 'eslint-plugin-oxlint';
+import perfectionist from 'eslint-plugin-perfectionist';
import pluginVue from 'eslint-plugin-vue';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
@@ -51,4 +52,14 @@ export default [
// ],
},
},
+
+ // https://perfectionist.dev/guide/getting-started
+ {
+ plugins: {
+ perfectionist,
+ },
+ rules: {
+ 'perfectionist/sort-imports': ['error'],
+ },
+ },
];
diff --git a/fake/user.fake.ts b/fake/user.fake.ts
index 5ce71a8..8be1926 100644
--- a/fake/user.fake.ts
+++ b/fake/user.fake.ts
@@ -1,7 +1,7 @@
+import { faker } from '@faker-js/faker';
// fake/user.fake.ts
import Mock from 'mockjs';
import { defineFakeRoute } from 'vite-plugin-fake-server/client';
-import { faker } from '@faker-js/faker';
export default defineFakeRoute([
{
diff --git a/package.json b/package.json
index 716f108..2318599 100644
--- a/package.json
+++ b/package.json
@@ -98,6 +98,7 @@
"eruda": "^3.4.1",
"eslint": "^9.18.0",
"eslint-plugin-oxlint": "^0.15.5",
+ "eslint-plugin-perfectionist": "^4.7.0",
"eslint-plugin-vue": "^9.32.0",
"husky": "^9.1.7",
"jsdom": "^25.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fd738cb..5d1d366 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -159,7 +159,7 @@ importers:
version: 4.1.1(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass-embedded@1.83.4)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.2))
'@vitest/eslint-plugin':
specifier: ^1.1.25
- version: 1.1.25(@typescript-eslint/utils@8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)
+ version: 1.1.25(@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)
'@vue/eslint-config-prettier':
specifier: ^10.2.0
version: 10.2.0(eslint@9.18.0(jiti@2.4.2))(prettier@3.4.2)
@@ -190,6 +190,9 @@ importers:
eslint-plugin-oxlint:
specifier: ^0.15.5
version: 0.15.5
+ eslint-plugin-perfectionist:
+ specifier: ^4.7.0
+ version: 4.7.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)
eslint-plugin-vue:
specifier: ^9.32.0
version: 9.32.0(eslint@9.18.0(jiti@2.4.2))
@@ -1405,6 +1408,10 @@ packages:
resolution: {integrity: sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/scope-manager@8.21.0':
+ resolution: {integrity: sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript-eslint/type-utils@8.20.0':
resolution: {integrity: sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1420,6 +1427,10 @@ packages:
resolution: {integrity: sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/types@8.21.0':
+ resolution: {integrity: sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript-eslint/typescript-estree@8.19.1':
resolution: {integrity: sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1432,6 +1443,12 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/typescript-estree@8.21.0':
+ resolution: {integrity: sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <5.8.0'
+
'@typescript-eslint/utils@8.20.0':
resolution: {integrity: sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1439,6 +1456,13 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/utils@8.21.0':
+ resolution: {integrity: sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.8.0'
+
'@typescript-eslint/visitor-keys@8.19.1':
resolution: {integrity: sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1447,6 +1471,10 @@ packages:
resolution: {integrity: sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/visitor-keys@8.21.0':
+ resolution: {integrity: sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@unhead/dom@1.11.18':
resolution: {integrity: sha512-zQuJUw/et9zYEV0SZWTDX23IgurwMaXycAuxt4L6OgNL0T4TWP3a0J/Vm3Q02hmdNo/cPKeVBrwBdnFUXjGU4w==}
@@ -2769,6 +2797,12 @@ packages:
eslint-plugin-oxlint@0.15.5:
resolution: {integrity: sha512-oPkAGZ2ZJfHmHPiVa+aMN7Sotw1Hh/ZKJnxWnrlhVTQzgOBox9lXG0rHvYeyeewSLjuL/hyT67+IZ64nw8k55g==}
+ eslint-plugin-perfectionist@4.7.0:
+ resolution: {integrity: sha512-e2ODzm2SsAztFWY3ZRJd1K702vyl8Sapacjc3JluOW294CfA3+jfjin+UxjcrK48EvlNIMOp+JJB9N54YR2LRw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ eslint: '>=8.0.0'
+
eslint-plugin-prettier@5.2.3:
resolution: {integrity: sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -3821,6 +3855,10 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ natural-orderby@5.0.0:
+ resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==}
+ engines: {node: '>=18'}
+
needle@3.3.1:
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
engines: {node: '>= 4.4.x'}
@@ -6489,6 +6527,11 @@ snapshots:
'@typescript-eslint/types': 8.20.0
'@typescript-eslint/visitor-keys': 8.20.0
+ '@typescript-eslint/scope-manager@8.21.0':
+ dependencies:
+ '@typescript-eslint/types': 8.21.0
+ '@typescript-eslint/visitor-keys': 8.21.0
+
'@typescript-eslint/type-utils@8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)':
dependencies:
'@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.2)
@@ -6504,6 +6547,8 @@ snapshots:
'@typescript-eslint/types@8.20.0': {}
+ '@typescript-eslint/types@8.21.0': {}
+
'@typescript-eslint/typescript-estree@8.19.1(typescript@5.7.2)':
dependencies:
'@typescript-eslint/types': 8.19.1
@@ -6532,6 +6577,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/typescript-estree@8.21.0(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/types': 8.21.0
+ '@typescript-eslint/visitor-keys': 8.21.0
+ debug: 4.4.0
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.6.3
+ ts-api-utils: 2.0.0(typescript@5.7.2)
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/utils@8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
@@ -6543,6 +6602,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
+ '@typescript-eslint/scope-manager': 8.21.0
+ '@typescript-eslint/types': 8.21.0
+ '@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.2)
+ eslint: 9.18.0(jiti@2.4.2)
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/visitor-keys@8.19.1':
dependencies:
'@typescript-eslint/types': 8.19.1
@@ -6553,6 +6623,11 @@ snapshots:
'@typescript-eslint/types': 8.20.0
eslint-visitor-keys: 4.2.0
+ '@typescript-eslint/visitor-keys@8.21.0':
+ dependencies:
+ '@typescript-eslint/types': 8.21.0
+ eslint-visitor-keys: 4.2.0
+
'@unhead/dom@1.11.18':
dependencies:
'@unhead/schema': 1.11.18
@@ -6906,9 +6981,9 @@ snapshots:
vite: 6.0.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.2)(sass-embedded@1.83.4)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)
vue: 3.5.13(typescript@5.7.2)
- '@vitest/eslint-plugin@1.1.25(@typescript-eslint/utils@8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)':
+ '@vitest/eslint-plugin@1.1.25(@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)':
dependencies:
- '@typescript-eslint/utils': 8.20.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)
+ '@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)
eslint: 9.18.0(jiti@2.4.2)
optionalDependencies:
typescript: 5.7.2
@@ -8185,6 +8260,16 @@ snapshots:
dependencies:
jsonc-parser: 3.3.1
+ eslint-plugin-perfectionist@4.7.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2):
+ dependencies:
+ '@typescript-eslint/types': 8.21.0
+ '@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.2)
+ eslint: 9.18.0(jiti@2.4.2)
+ natural-orderby: 5.0.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
eslint-plugin-prettier@5.2.3(eslint-config-prettier@10.0.1(eslint@9.18.0(jiti@2.4.2)))(eslint@9.18.0(jiti@2.4.2))(prettier@3.4.2):
dependencies:
eslint: 9.18.0(jiti@2.4.2)
@@ -9286,6 +9371,8 @@ snapshots:
natural-compare@1.4.0: {}
+ natural-orderby@5.0.0: {}
+
needle@3.3.1:
dependencies:
iconv-lite: 0.6.3
diff --git a/src/layouts/sakai-vue/AppConfigurator.vue b/src/layouts/sakai-vue/AppConfigurator.vue
index a47fc19..8cfce46 100644
--- a/src/layouts/sakai-vue/AppConfigurator.vue
+++ b/src/layouts/sakai-vue/AppConfigurator.vue
@@ -3,6 +3,7 @@ import { $t, updatePreset, updateSurfacePalette } from '@primevue/themes';
import Aura from '@primevue/themes/aura';
import Lara from '@primevue/themes/lara';
import { ref } from 'vue';
+
import { useLayout } from './composables/layout';
const { layoutConfig, isDarkTheme } = useLayout();
diff --git a/src/layouts/sakai-vue/AppLayout.vue b/src/layouts/sakai-vue/AppLayout.vue
index 3f17500..bd95ae1 100644
--- a/src/layouts/sakai-vue/AppLayout.vue
+++ b/src/layouts/sakai-vue/AppLayout.vue
@@ -2,6 +2,7 @@
import './styles/layout.scss';
import { computed, ref, watch } from 'vue';
+
import AppFooter from './AppFooter.vue';
import AppSidebar from './AppSidebar.vue';
import AppTopbar from './AppTopbar.vue';
diff --git a/src/layouts/sakai-vue/AppMenu.vue b/src/layouts/sakai-vue/AppMenu.vue
index 9e3aadc..60b56ed 100644
--- a/src/layouts/sakai-vue/AppMenu.vue
+++ b/src/layouts/sakai-vue/AppMenu.vue
@@ -1,7 +1,8 @@
diff --git a/src/plugins/_.ts b/src/plugins/_.ts
index 2993e6d..dde304a 100644
--- a/src/plugins/_.ts
+++ b/src/plugins/_.ts
@@ -1,5 +1,5 @@
-import { createHead } from '@unhead/vue';
import { autoAnimatePlugin } from '@formkit/auto-animate/vue';
+import { createHead } from '@unhead/vue';
export function install({ app }: { app: import('vue').App }) {
app.config.globalProperties.$__DEV__ = $__DEV__;
diff --git a/src/plugins/vue-i18n.ts b/src/plugins/vue-i18n.ts
index 6f50a02..94abbf8 100644
--- a/src/plugins/vue-i18n.ts
+++ b/src/plugins/vue-i18n.ts
@@ -1,10 +1,9 @@
-import { createI18n } from 'vue-i18n';
-
/* https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#static-bundle-importing
* All i18n resources specified in the plugin `include` option can be loaded
* at once using the import syntax
*/
import messages from '@intlify/unplugin-vue-i18n/messages';
+import { createI18n } from 'vue-i18n';
export function install({ app }: { app: import('vue').App }) {
app.use(
diff --git a/src/stores/counter.ts b/src/stores/counter.ts
index 733543d..1b46411 100644
--- a/src/stores/counter.ts
+++ b/src/stores/counter.ts
@@ -1,5 +1,5 @@
-import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
+import { computed, ref } from 'vue';
export const useCounterStore = defineStore(
'counter',
diff --git a/src/styles/index.ts b/src/styles/index.ts
index c1433a3..8e7524d 100644
--- a/src/styles/index.ts
+++ b/src/styles/index.ts
@@ -1,6 +1,5 @@
//
import 'nprogress/nprogress.css';
-
// https://unocss.dev/guide/style-reset#tailwind-compat //
// import '@unocss/reset/tailwind-compat.css';
import '@unocss/reset/tailwind.css';
@@ -9,6 +8,7 @@ import './base.css';
import './main.less';
import 'primeicons/primeicons.css';
+
import './reset-primevue.css';
import 'virtual:uno.css';
diff --git a/vite.config.ts b/vite.config.ts
index de69dab..c0dc306 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,8 +1,9 @@
-import { fileURLToPath, URL } from 'node:url';
-
// import { createSplitChunkOutput } from 'utils4u/rollup';
+
+import { fileURLToPath, URL } from 'node:url';
import { createViteProxy } from 'utils4u/vite';
import { defineConfig, loadEnv } from 'vite';
+
import { Plugins } from './vite.config.plugins';
// https://vitejs.dev/config/