@vc-shell/create-vc-app 1.1.58 → 1.1.60

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 (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.js +1 -1
  3. package/dist/templates/base/_package.json +5 -5
  4. package/dist/templates/base/src/bootstrap.ts +23 -0
  5. package/dist/templates/base/src/components/dashboard-widgets/Welcome.vue +51 -0
  6. package/dist/templates/base/src/locales/en.json +13 -3
  7. package/dist/templates/base/src/pages/Dashboard.vue +7 -0
  8. package/dist/templates/base/src/router/routes.ts +80 -78
  9. package/dist/templates/mocks/sample-data/constants.ts +89 -86
  10. package/dist/templates/modules/classic-module/composables/use{{ModuleNamePascalCase}}List/index.ts +40 -23
  11. package/dist/templates/modules/classic-module/pages/details.vue +68 -61
  12. package/dist/templates/modules/classic-module/pages/list.vue +32 -33
  13. package/dist/templates/sample/classic-module/composables/useDetails/index.ts +54 -41
  14. package/dist/templates/sample/classic-module/composables/useList/index.ts +30 -11
  15. package/dist/templates/sample/classic-module/pages/details.vue +11 -24
  16. package/dist/templates/sample/classic-module/pages/list.vue +31 -34
  17. package/package.json +2 -2
  18. package/dist/templates/modules/dynamic-module/composables/index.ts +0 -2
  19. package/dist/templates/modules/dynamic-module/composables/use{{ModuleNamePascalCase}}Details/index.ts +0 -37
  20. package/dist/templates/modules/dynamic-module/composables/use{{ModuleNamePascalCase}}List/index.ts +0 -49
  21. package/dist/templates/modules/dynamic-module/index.ts +0 -8
  22. package/dist/templates/modules/dynamic-module/locales/en.json +0 -35
  23. package/dist/templates/modules/dynamic-module/locales/index.ts +0 -2
  24. package/dist/templates/modules/dynamic-module/pages/details.ts +0 -20
  25. package/dist/templates/modules/dynamic-module/pages/index.ts +0 -4
  26. package/dist/templates/modules/dynamic-module/pages/list.ts +0 -35
  27. package/dist/templates/sample/dynamic-module/composables/index.ts +0 -2
  28. package/dist/templates/sample/dynamic-module/composables/useDetails/index.ts +0 -46
  29. package/dist/templates/sample/dynamic-module/composables/useList/index.ts +0 -50
  30. package/dist/templates/sample/dynamic-module/index.ts +0 -8
  31. package/dist/templates/sample/dynamic-module/locales/en.json +0 -69
  32. package/dist/templates/sample/dynamic-module/locales/index.ts +0 -2
  33. package/dist/templates/sample/dynamic-module/pages/details.ts +0 -100
  34. package/dist/templates/sample/dynamic-module/pages/index.ts +0 -4
  35. package/dist/templates/sample/dynamic-module/pages/list.ts +0 -80
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.1.60](https://github.com/VirtoCommerce/vc-shell/compare/v1.1.59...v1.1.60) (2025-07-17)
2
+
3
+
4
+ ### Features
5
+
6
+ * **create-vc-ap):** updated sample and base layout ([9ec1677](https://github.com/VirtoCommerce/vc-shell/commit/9ec1677dc52eb99b0238f9e466904185bbfc2acb))
7
+ * **create-vc-app:** implement initial dashboard setup with welcome widget and routing ([d924e71](https://github.com/VirtoCommerce/vc-shell/commit/d924e715467f766b88bd746ac31a7a2b4dec168f))
8
+
9
+
10
+
11
+ ## [1.1.59](https://github.com/VirtoCommerce/vc-shell/compare/v1.1.58...v1.1.59) (2025-07-11)
12
+
13
+
14
+
1
15
  ## [1.1.58](https://github.com/VirtoCommerce/vc-shell/compare/v1.1.57...v1.1.58) (2025-07-10)
2
16
 
3
17
 
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import c from "node:path";
6
6
  import s from "node:fs";
7
7
  import { fileURLToPath as Oe } from "node:url";
8
8
  import { cwd as Me, exit as Ee, argv as Te } from "node:process";
9
- const Ue = "1.1.58", I = {
9
+ const Ue = "1.1.60", I = {
10
10
  version: Ue
11
11
  };
12
12
  var Pe = typeof global == "object" && global && global.Object === Object && global, Le = typeof self == "object" && self && self.Object === Object && self, _e = Pe || Le || Function("return this")(), b = _e.Symbol, K = Object.prototype, ze = K.hasOwnProperty, De = K.toString, $ = b ? b.toStringTag : void 0;
@@ -23,9 +23,9 @@
23
23
  "@types/node": "^20.10.5",
24
24
  "@typescript-eslint/eslint-plugin": "^6.16.0",
25
25
  "@typescript-eslint/parser": "^6.16.0",
26
- "@vc-shell/api-client-generator": "^1.1.58",
27
- "@vc-shell/release-config": "^1.1.58",
28
- "@vc-shell/ts-config": "^1.1.58",
26
+ "@vc-shell/api-client-generator": "^1.1.60",
27
+ "@vc-shell/release-config": "^1.1.60",
28
+ "@vc-shell/ts-config": "^1.1.60",
29
29
  "@vitejs/plugin-vue": "^5.2.3",
30
30
  "@vue/eslint-config-prettier": "^9.0.0",
31
31
  "@vue/eslint-config-typescript": "^12.0.0",
@@ -53,8 +53,8 @@
53
53
  "vue-tsc": "^2.2.10"
54
54
  },
55
55
  "dependencies": {
56
- "@vc-shell/config-generator": "^1.1.58",
57
- "@vc-shell/framework": "^1.1.58",
56
+ "@vc-shell/config-generator": "^1.1.60",
57
+ "@vc-shell/framework": "^1.1.60",
58
58
  "@vueuse/core": "^10.7.1",
59
59
  "@vueuse/integrations": "^10.7.1",
60
60
  "cross-spawn": "^7.0.3",
@@ -0,0 +1,23 @@
1
+ import { addMenuItem, registerDashboardWidget } from "@vc-shell/framework";
2
+ import { App, markRaw } from "vue";
3
+ import Welcome from "./components/dashboard-widgets/Welcome.vue";
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
+ export function bootstrap(app: App) {
7
+ // Add Dashboard to main menu item
8
+ addMenuItem({
9
+ title: "SHELL.MENU.DASHBOARD",
10
+ icon: "lucide-home",
11
+ priority: 0,
12
+ url: "/",
13
+ });
14
+
15
+ // Register Dashboard Welcome Widget
16
+ registerDashboardWidget({
17
+ id: "welcome-widget",
18
+ name: "Welcome",
19
+ component: markRaw(Welcome),
20
+ size: { width: 6, height: 6 },
21
+ position: { x: 0, y: 0 },
22
+ });
23
+ }
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <div class="dashboard-widget-welcome">
3
+ <div class="dashboard-widget-welcome__welcome-image">
4
+ <img
5
+ :src="Welcome"
6
+ alt="Welcome"
7
+ />
8
+ </div>
9
+ <h1 class="dashboard-widget-welcome__welcome-title">{{ $t("SHELL.DASHBOARD.WELCOME.TITLE") }}</h1>
10
+ <p class="dashboard-widget-welcome__welcome-description">
11
+ {{ $t("SHELL.DASHBOARD.WELCOME.DESCRIPTION") }}
12
+ </p>
13
+ <VcButton
14
+ variant="secondary"
15
+ size="base"
16
+ >{{ $t("SHELL.DASHBOARD.WELCOME.GET_STARTED") }}</VcButton
17
+ >
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ // eslint-disable-next-line import/no-unresolved
23
+ import Welcome from "/assets/welcome.png";
24
+ </script>
25
+
26
+ <style lang="scss">
27
+ :root {
28
+ --dashboard-widget-welcome-background: linear-gradient(128deg, #e187f3 -18.35%, #45a5f5 96.57%);
29
+ --dashboard-widget-welcome-title-color: var(--additional-50);
30
+ --dashboard-widget-welcome-description-color: var(--additional-50);
31
+ --dashboard-widget-welcome-button-color: var(--additional-50);
32
+ --dashboard-widget-welcome-button-background: var(--additional-50);
33
+ }
34
+
35
+ .dashboard-widget-welcome {
36
+ background: var(--dashboard-widget-welcome-background);
37
+ @apply tw-h-full tw-p-6 tw-text-center tw-text-[color:var(--dashboard-widget-welcome-title-color)] tw-gap-6 tw-flex tw-flex-col tw-items-center;
38
+
39
+ &__welcome-image {
40
+ @apply tw-flex tw-justify-center tw-max-w-[80%] tw-h-[40%];
41
+ }
42
+
43
+ &__welcome-title {
44
+ @apply tw-text-2xl tw-font-semibold;
45
+ }
46
+
47
+ &__welcome-description {
48
+ @apply tw-whitespace-break-spaces tw-text-s tw-max-w-[90%] tw-mx-auto tw-leading-5 tw-font-semibold;
49
+ }
50
+ }
51
+ </style>
@@ -1,3 +1,13 @@
1
- {
2
- "language_name": "English"
3
- }
1
+ {
2
+ "language_name": "English",
3
+ "SHELL": {
4
+ "DASHBOARD": {
5
+ "TITLE": "Dashboard",
6
+ "WELCOME": {
7
+ "TITLE": "Welcome",
8
+ "DESCRIPTION": "Welcome to Vendor portal! We're so excited to have you on board. \n To get started, we recommend exploring the dashboard and personalizing your settings to match your preferences.",
9
+ "GET_STARTED": "Get started"
10
+ }
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,7 @@
1
+ <template>
2
+ <DraggableDashboard />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import { DraggableDashboard } from "@vc-shell/framework";
7
+ </script>
@@ -1,78 +1,80 @@
1
- import { RouteRecordRaw } from "vue-router";
2
- import App from "../pages/App.vue";
3
- import { Invite, Login, ResetPassword, useBladeNavigation, ChangePasswordPage } from "@vc-shell/framework";
4
- // eslint-disable-next-line import/no-unresolved
5
- import whiteLogoImage from "/assets/logo-white.svg";
6
- // eslint-disable-next-line import/no-unresolved
7
- import bgImage from "/assets/background.jpg";
8
-
9
- export const routes: RouteRecordRaw[] = [
10
- {
11
- path: "/",
12
- component: App,
13
- name: "App",
14
- meta: {
15
- root: true,
16
- },
17
- children: [],
18
- redirect: (to) => {
19
- if (to.name === "App") {
20
- return { path: "/{{ModuleName}}", params: to.params };
21
- }
22
- return to.path;
23
- },
24
- },
25
- {
26
- name: "Login",
27
- path: "/login",
28
- component: Login,
29
- props: () => ({
30
- logo: whiteLogoImage,
31
- background: bgImage,
32
- title: "{{AppNameSentenceCase}}",
33
- }),
34
- },
35
- {
36
- name: "Invite",
37
- path: "/invite",
38
- component: Invite,
39
- props: (route) => ({
40
- userId: route.query.userId,
41
- token: route.query.token,
42
- userName: route.query.userName,
43
- logo: whiteLogoImage,
44
- background: bgImage,
45
- }),
46
- },
47
- {
48
- name: "ResetPassword",
49
- path: "/resetpassword",
50
- component: ResetPassword,
51
- props: (route) => ({
52
- userId: route.query.userId,
53
- token: route.query.token,
54
- userName: route.query.userName,
55
- logo: whiteLogoImage,
56
- background: bgImage,
57
- }),
58
- },
59
- {
60
- name: "ChangePassword",
61
- path: "/changepassword",
62
- component: ChangePasswordPage,
63
- meta: {
64
- forced: true,
65
- },
66
- props: (route) => ({
67
- background: bgImage,
68
- }),
69
- },
70
- {
71
- path: "/:pathMatch(.*)*",
72
- component: App,
73
- beforeEnter: async (to) => {
74
- const { routeResolver } = useBladeNavigation();
75
- return routeResolver(to);
76
- },
77
- },
78
- ];
1
+ import { RouteRecordRaw } from "vue-router";
2
+ import App from "../pages/App.vue";
3
+ import Dashboard from "../pages/Dashboard.vue";
4
+ import { Invite, Login, ResetPassword, useBladeNavigation, ChangePasswordPage } from "@vc-shell/framework";
5
+ // eslint-disable-next-line import/no-unresolved
6
+ import whiteLogoImage from "/assets/logo-white.svg";
7
+ // eslint-disable-next-line import/no-unresolved
8
+ import bgImage from "/assets/background.jpg";
9
+
10
+ export const routes: RouteRecordRaw[] = [
11
+ {
12
+ path: "/",
13
+ component: App,
14
+ name: "App",
15
+ meta: {
16
+ root: true,
17
+ },
18
+ children: [
19
+ {
20
+ name: "Dashboard",
21
+ path: "",
22
+ alias: `/`,
23
+ component: Dashboard,
24
+ },
25
+ ],
26
+ },
27
+ {
28
+ name: "Login",
29
+ path: "/login",
30
+ component: Login,
31
+ props: () => ({
32
+ logo: whiteLogoImage,
33
+ background: bgImage,
34
+ title: "{{AppNameSentenceCase}}",
35
+ }),
36
+ },
37
+ {
38
+ name: "Invite",
39
+ path: "/invite",
40
+ component: Invite,
41
+ props: (route) => ({
42
+ userId: route.query.userId,
43
+ token: route.query.token,
44
+ userName: route.query.userName,
45
+ logo: whiteLogoImage,
46
+ background: bgImage,
47
+ }),
48
+ },
49
+ {
50
+ name: "ResetPassword",
51
+ path: "/resetpassword",
52
+ component: ResetPassword,
53
+ props: (route) => ({
54
+ userId: route.query.userId,
55
+ token: route.query.token,
56
+ userName: route.query.userName,
57
+ logo: whiteLogoImage,
58
+ background: bgImage,
59
+ }),
60
+ },
61
+ {
62
+ name: "ChangePassword",
63
+ path: "/changepassword",
64
+ component: ChangePasswordPage,
65
+ meta: {
66
+ forced: true,
67
+ },
68
+ props: (route) => ({
69
+ background: bgImage,
70
+ }),
71
+ },
72
+ {
73
+ path: "/:pathMatch(.*)*",
74
+ component: App,
75
+ beforeEnter: async (to) => {
76
+ const { routeResolver } = useBladeNavigation();
77
+ return routeResolver(to);
78
+ },
79
+ },
80
+ ];
@@ -1,86 +1,89 @@
1
- interface MockedItem {
2
- imgSrc: string;
3
- name: string;
4
- id: string;
5
- description: string;
6
- price: number;
7
- salePrice: number;
8
- guid: string;
9
- currency: string;
10
- }
11
-
12
- interface MockedQuery {
13
- keyword?: string;
14
- }
15
-
16
- const mockedItems: MockedItem[] = [
17
- {
18
- id: "beb211ea-1379-5a79-832c-9577ad387feb",
19
- name: "Product 1",
20
- imgSrc: "https://via.placeholder.com/150",
21
- description: "Product 1 description",
22
- price: 100,
23
- salePrice: 90,
24
- guid: "a1e26bcd-2704-5a3f-b97c-3e32e3d77a38",
25
- currency: "USD",
26
- },
27
- {
28
- id: "44b96758-792a-5449-b649-f2a0cd614c4b",
29
- name: "Product 2",
30
- imgSrc: "https://via.placeholder.com/150",
31
- description: "Product 2 description",
32
- price: 200,
33
- salePrice: 90,
34
- guid: "0ab995c0-3798-5011-a4ae-498e4c683cfd",
35
- currency: "USD",
36
- },
37
- {
38
- id: "605b2bfb-ba13-5687-91d5-0261b4b60524",
39
- name: "Product 3",
40
- imgSrc: "https://via.placeholder.com/150",
41
- description: "Product 3 description",
42
- price: 300,
43
- salePrice: 90,
44
- guid: "8a9b6954-7bf7-58b2-a146-c68e06fa7bb4",
45
- currency: "USD",
46
- },
47
- {
48
- id: "5ca8185c-0c28-59bf-ab40-991f134e6db3",
49
- name: "Product 4",
50
- imgSrc: "https://via.placeholder.com/150",
51
- description: "Product 4 description",
52
- price: 400,
53
- salePrice: 90,
54
- guid: "261364c5-f976-5c86-a92c-b0f0ea14efc7",
55
- currency: "USD",
56
- },
57
- {
58
- id: "077930cb-0874-5f85-9a5b-daafdd0bf860",
59
- name: "Product 5",
60
- imgSrc: "https://via.placeholder.com/150",
61
- description: "Product 5 description",
62
- price: 500,
63
- salePrice: 90,
64
- guid: "74d302ef-31e6-5432-91f1-d92c87ee2d2a",
65
- currency: "USD",
66
- },
67
- ];
68
-
69
- const currencyOptions = [
70
- {
71
- value: "USD",
72
- label: "USD",
73
- },
74
- {
75
- value: "EUR",
76
- label: "EUR",
77
- },
78
- {
79
- value: "GBP",
80
- label: "GBP",
81
- },
82
- ];
83
-
84
- export { mockedItems, currencyOptions };
85
-
86
- export type { MockedItem, MockedQuery };
1
+ interface MockedItem {
2
+ imgSrc: string;
3
+ name: string;
4
+ id: string;
5
+ description: string;
6
+ price: number;
7
+ salePrice: number;
8
+ guid: string;
9
+ currency: string;
10
+ }
11
+
12
+ interface MockedQuery {
13
+ keyword?: string;
14
+ take?: number;
15
+ skip?: number;
16
+ sort?: string;
17
+ }
18
+
19
+ const mockedItems: MockedItem[] = [
20
+ {
21
+ id: "beb211ea-1379-5a79-832c-9577ad387feb",
22
+ name: "Product 1",
23
+ imgSrc: "https://via.placeholder.com/150",
24
+ description: "Product 1 description",
25
+ price: 100,
26
+ salePrice: 90,
27
+ guid: "a1e26bcd-2704-5a3f-b97c-3e32e3d77a38",
28
+ currency: "USD",
29
+ },
30
+ {
31
+ id: "44b96758-792a-5449-b649-f2a0cd614c4b",
32
+ name: "Product 2",
33
+ imgSrc: "https://via.placeholder.com/150",
34
+ description: "Product 2 description",
35
+ price: 200,
36
+ salePrice: 90,
37
+ guid: "0ab995c0-3798-5011-a4ae-498e4c683cfd",
38
+ currency: "USD",
39
+ },
40
+ {
41
+ id: "605b2bfb-ba13-5687-91d5-0261b4b60524",
42
+ name: "Product 3",
43
+ imgSrc: "https://via.placeholder.com/150",
44
+ description: "Product 3 description",
45
+ price: 300,
46
+ salePrice: 90,
47
+ guid: "8a9b6954-7bf7-58b2-a146-c68e06fa7bb4",
48
+ currency: "USD",
49
+ },
50
+ {
51
+ id: "5ca8185c-0c28-59bf-ab40-991f134e6db3",
52
+ name: "Product 4",
53
+ imgSrc: "https://via.placeholder.com/150",
54
+ description: "Product 4 description",
55
+ price: 400,
56
+ salePrice: 90,
57
+ guid: "261364c5-f976-5c86-a92c-b0f0ea14efc7",
58
+ currency: "USD",
59
+ },
60
+ {
61
+ id: "077930cb-0874-5f85-9a5b-daafdd0bf860",
62
+ name: "Product 5",
63
+ imgSrc: "https://via.placeholder.com/150",
64
+ description: "Product 5 description",
65
+ price: 500,
66
+ salePrice: 90,
67
+ guid: "74d302ef-31e6-5432-91f1-d92c87ee2d2a",
68
+ currency: "USD",
69
+ },
70
+ ];
71
+
72
+ const currencyOptions = [
73
+ {
74
+ value: "USD",
75
+ label: "USD",
76
+ },
77
+ {
78
+ value: "EUR",
79
+ label: "EUR",
80
+ },
81
+ {
82
+ value: "GBP",
83
+ label: "GBP",
84
+ },
85
+ ];
86
+
87
+ export { mockedItems, currencyOptions };
88
+
89
+ export type { MockedItem, MockedQuery };
@@ -1,23 +1,40 @@
1
- import { computed, ref } from "vue";
2
- import { useAsync, useLoading } from "@vc-shell/framework";
3
-
4
- export default () => {
5
- const data = ref([]);
6
- const dataRes = ref();
7
-
8
- // Implement your own load function
9
- const { loading: itemLoading, action: getItems } = useAsync(async (payload) => {
10
- data.value = [];
11
- });
12
-
13
- const loading = useLoading(itemLoading);
14
-
15
- return {
16
- data: computed(() => data.value),
17
- loading: computed(() => loading.value),
18
- totalCount: computed(() => dataRes.value?.totalCount),
19
- pages: computed(() => Math.ceil(dataRes.value?.totalCount / 20)),
20
- currentPage: 0 / Math.max(1, 20) + 1,
21
- getItems,
22
- };
23
- };
1
+ import { computed, ref } from "vue";
2
+ import { useAsync, useLoading } from "@vc-shell/framework";
3
+
4
+ // Replace with the actual search query interface from the API client
5
+ interface SearchQuery {
6
+ take?: number;
7
+ skip?: number;
8
+ sort?: string;
9
+ }
10
+
11
+ export default (options?: { pageSize?: number, sort?: string }) => {
12
+ const pageSize = options?.pageSize || 20;
13
+ const searchResult = ref();
14
+ const searchQuery = ref<SearchQuery>({
15
+ take: pageSize,
16
+ skip: 0,
17
+ sort: options?.sort || "createdDate:DESC",
18
+ });
19
+
20
+ // Implement your own load function
21
+ const { loading: itemLoading, action: getItems } = useAsync<SearchQuery>(async (payload) => {
22
+ searchQuery.value = { ...searchQuery.value, ...payload };
23
+ searchResult.value = {
24
+ totalCount: 0,
25
+ items: [],
26
+ };
27
+ });
28
+
29
+ const loading = useLoading(itemLoading);
30
+
31
+ return {
32
+ data: computed(() => searchResult.value?.items),
33
+ loading: computed(() => loading.value),
34
+ totalCount: computed(() => searchResult.value?.totalCount || 0),
35
+ pages: computed(() => Math.ceil((searchResult.value?.totalCount || 1) / pageSize)),
36
+ currentPage: computed(() => Math.ceil((searchQuery.value?.skip || 0) / Math.max(1, pageSize) + 1)),
37
+ getItems,
38
+ searchQuery,
39
+ };
40
+ };