zmp-cli 3.5.4 → 3.6.0

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 (32) hide show
  1. package/.vscode/launch.json +21 -0
  2. package/.vscode/settings.json +2 -1
  3. package/create/templates/common/tailwind/tailwind.config.js +1 -1
  4. package/create/templates/generate-index.js +1 -1
  5. package/create/templates/generate-routes.js +2 -2
  6. package/create/templates/generate-store.js +33 -0
  7. package/create/templates/generate-styles.js +19 -10
  8. package/create/templates/vue/components/header.vue +28 -0
  9. package/create/templates/vue/components/sun-and-moon.vue +34 -0
  10. package/create/templates/vue/copy-assets.js +28 -7
  11. package/create/templates/vue/dist/copy-assets.dev.js +1 -1
  12. package/create/templates/vue/generate-home-page.js +49 -103
  13. package/create/templates/vue/generate-root.js +30 -193
  14. package/create/templates/vue/generate-routes.js +2 -87
  15. package/create/templates/vue/generate-scripts.js +8 -3
  16. package/create/templates/vue/global-components.d.ts +121 -0
  17. package/create/templates/vue/icons/moon.svg +3 -0
  18. package/create/templates/vue/icons/sun.svg +3 -0
  19. package/create/templates/vue/pages/settings.vue +14 -158
  20. package/create/templates/vue/vite.config.js +11 -0
  21. package/create/utils/generate-package-json.js +14 -6
  22. package/create/utils/get-options.js +7 -8
  23. package/index.js +1 -0
  24. package/package.json +1 -1
  25. package/start/dist/index.dev.js +65 -28
  26. package/start/index.js +41 -4
  27. package/utils/find-files-by-ext.js +1 -1
  28. package/create/templates/common/icons/128x128.png +0 -0
  29. package/create/templates/common/icons/144x144.png +0 -0
  30. package/create/templates/common/icons/152x152.png +0 -0
  31. package/create/templates/common/icons/192x192.png +0 -0
  32. package/create/templates/common/icons/256x256.png +0 -0
@@ -0,0 +1,21 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "pwa-node",
9
+ "request": "launch",
10
+ "name": "Launch Program",
11
+ "skipFiles": [
12
+ "<node_internals>/**"
13
+ ],
14
+ "program": "${workspaceFolder}/index.js",
15
+ "args": [
16
+ "init"
17
+ ],
18
+ "console": "integratedTerminal"
19
+ }
20
+ ]
21
+ }
@@ -1,3 +1,4 @@
1
1
  {
2
- "prettier.trailingComma": "none"
2
+ "prettier.trailingComma": "none",
3
+ "workbench.colorTheme": "GitHub Dark Default"
3
4
  }
@@ -1,7 +1,7 @@
1
1
  module.exports = {
2
2
  purge: {
3
3
  enabled: true,
4
- content: ['./src/**/*.{js,jsx,ts,tsx}'],
4
+ content: ['./src/**/*.{js,jsx,ts,tsx,vue}'],
5
5
  },
6
6
  theme: {
7
7
  extend: {},
@@ -10,7 +10,7 @@ module.exports = (options) => {
10
10
  const scripts = `
11
11
  <!-- built script files will be auto injected -->
12
12
  ${
13
- framework === 'react'
13
+ framework === 'react' || framework === 'vue'
14
14
  ? `<script type="module" src="${srcFolder}app.js"></script>`
15
15
  : ''
16
16
  }
@@ -1,5 +1,5 @@
1
1
  // const generateCoreRoutes = require('./core/generate-routes');
2
- // const generateVueRoutes = require('./vue/generate-routes');
2
+ const generateVueRoutes = require('./vue/generate-routes');
3
3
  const generateReactRoutes = require('./react/generate-routes');
4
4
  const generateReactTsRoutes = require('./react-typescript/generate-routes');
5
5
  // const generateSvelteRoutes = require('./svelte/generate-routes');
@@ -7,7 +7,7 @@ const generateReactTsRoutes = require('./react-typescript/generate-routes');
7
7
  module.exports = (options) => {
8
8
  const { framework } = options;
9
9
  // if (framework === 'core') return generateCoreRoutes(options);
10
- // if (framework === 'vue') return generateVueRoutes(options);
10
+ if (framework === 'vue') return generateVueRoutes(options);
11
11
  if (framework === 'react') return generateReactRoutes(options);
12
12
  if (framework === 'react-typescript') return generateReactTsRoutes(options);
13
13
 
@@ -4,6 +4,39 @@ const templateIf = require('../utils/template-if');
4
4
 
5
5
  module.exports = (options) => {
6
6
  const { framework } = options;
7
+ if (framework === 'vue') {
8
+ return indent(0, `
9
+ import { createStore } from 'zmp-core/lite';
10
+ const store = createStore({
11
+ state: {
12
+ user: {
13
+ id: '',
14
+ name: '',
15
+ avatar: ''
16
+ },
17
+ darkMode: false,
18
+ },
19
+ getters: {
20
+ user({ state }) {
21
+ return state.user
22
+ },
23
+ darkMode({ state }) {
24
+ return state.darkMode
25
+ }
26
+ },
27
+ actions: {
28
+ setUser({ state }, data) {
29
+ state.user = { ...state.user, ...data }
30
+ },
31
+ setDarkMode({ state }, dark) {
32
+ state.darkMode = dark
33
+ }
34
+ },
35
+ })
36
+
37
+ export default store;
38
+ `);
39
+ }
7
40
  return indent(0, `
8
41
  import { createStore } from 'zmp-core${framework === 'core' ? '' : '/lite'}';
9
42
  const store = createStore({
@@ -2,7 +2,7 @@ const indent = require('../utils/indent');
2
2
  const { colorThemeCSSProperties } = require('../utils/colors');
3
3
 
4
4
  module.exports = (options) => {
5
- const { template, theming } = options;
5
+ const { template, theming, includeTailwind } = options;
6
6
  const { customColor, color, fillBars } = theming;
7
7
 
8
8
  let styles = '';
@@ -19,18 +19,18 @@ module.exports = (options) => {
19
19
  /* Custom color theme properties */
20
20
  :root {
21
21
  ${Object.keys(customProps)
22
- .filter(
23
- (prop) =>
24
- prop !== '--zmp-tabbar-fill-link-active-color' &&
25
- prop !== '--zmp-tabbar-fill-link-active-border-color'
26
- )
27
- .map((prop) => `${prop}: ${customProps[prop]};`)
28
- .join('\n ')}
22
+ .filter(
23
+ (prop) =>
24
+ prop !== '--zmp-tabbar-fill-link-active-color' &&
25
+ prop !== '--zmp-tabbar-fill-link-active-border-color'
26
+ )
27
+ .map((prop) => `${prop}: ${customProps[prop]};`)
28
+ .join('\n ')}
29
29
  }
30
30
  :root.theme-dark,:root .theme-dark {
31
31
  ${Object.keys(customProps)
32
- .map((prop) => `${prop}: ${customProps[prop]};`)
33
- .join('\n ')}
32
+ .map((prop) => `${prop}: ${customProps[prop]};`)
33
+ .join('\n ')}
34
34
  }
35
35
  `
36
36
  );
@@ -44,6 +44,15 @@ module.exports = (options) => {
44
44
  );
45
45
  }
46
46
 
47
+ if (includeTailwind) {
48
+ styles += indent(
49
+ 0,
50
+ `
51
+ @import "./tailwind.css";
52
+ `
53
+ );
54
+ }
55
+
47
56
  if (template === 'split-view') {
48
57
  styles += indent(
49
58
  0,
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <zmp-navbar>
3
+ <zmp-nav-left>
4
+ <zmp-skeleton-avatar v-if="!user.id" class="pt-2"></zmp-skeleton-avatar>
5
+ <zmp-avatar v-else :src="user.avatar" online />
6
+ </zmp-nav-left>
7
+ <zmp-nav-title v-if="!user.id">
8
+ <zmp-skeleton-text>
9
+ <zmp-title class="mb-0">Lorem ipsum</zmp-title>
10
+ </zmp-skeleton-text>
11
+ <zmp-skeleton-text>Lorem ipsum</zmp-skeleton-text>
12
+ </zmp-nav-title>
13
+ <zmp-nav-title v-else>
14
+ <zmp-title class="mb-0">{{ user.name }}</zmp-title>
15
+ <zmp-text class="mb-0">{{ user.id }}</zmp-text>
16
+ </zmp-nav-title>
17
+ <zmp-nav-right>
18
+ <sun-and-moon />
19
+ </zmp-nav-right>
20
+ </zmp-navbar>
21
+ </template>
22
+
23
+ <script setup>
24
+ import { useStore } from "zmp-vue";
25
+ import SunAndMoon from "./sun-and-moon.vue";
26
+
27
+ const user = useStore('user')
28
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <zmp-button
3
+ small
4
+ class="sun-moon"
5
+ @click="setLayoutTheme"
6
+ type-name="primary"
7
+ round
8
+ :color="darkMode ? 'gray' : 'default'"
9
+ >
10
+ <img :src="icon" alt="switch-mode" />
11
+ </zmp-button>
12
+ </template>
13
+
14
+ <script setup>
15
+ import { useStore } from 'zmp-vue';
16
+ import { computed } from 'vue';
17
+ import store from '../store';
18
+ import sun from '../static/icons/sun.svg';
19
+ import moon from '../static/icons/moon.svg';
20
+
21
+ const darkMode = useStore('darkMode');
22
+
23
+ const icon = computed(() => (darkMode.value ? moon : sun));
24
+
25
+ const setLayoutTheme = () => {
26
+ store.dispatch('setDarkMode', !darkMode.value);
27
+ };
28
+ </script>
29
+
30
+ <style scoped>
31
+ .sun-moon {
32
+ padding: 0;
33
+ }
34
+ </style>
@@ -5,15 +5,11 @@ const generateStore = require('../generate-store');
5
5
 
6
6
  module.exports = (options) => {
7
7
  const cwd = options.cwd || process.cwd();
8
- const { template, bundler } = options;
8
+ const { bundler } = options;
9
9
  const toCopy = [];
10
10
 
11
11
  // Copy Pages
12
- const pages = [
13
- ...(template !== 'blank' ? ['404', 'about', 'dynamic-route', 'form'] : []),
14
- ...(template === 'tabs' ? ['catalog', 'product', 'settings'] : []),
15
- ...(template === 'split-view' ? ['left-page-1', 'left-page-2'] : []),
16
- ];
12
+ const pages = ['settings'];
17
13
 
18
14
  pages.forEach((p) => {
19
15
  const src = path.resolve(__dirname, 'pages', `${p}.vue`);
@@ -25,7 +21,7 @@ module.exports = (options) => {
25
21
  });
26
22
  toCopy.push({
27
23
  content: generateHomePage(options),
28
- to: path.resolve(cwd, 'src', 'pages', 'home.vue'),
24
+ to: path.resolve(cwd, 'src', 'pages', 'index.vue'),
29
25
  });
30
26
  toCopy.push({
31
27
  content: generateRoot(options),
@@ -35,6 +31,31 @@ module.exports = (options) => {
35
31
  content: generateStore(options),
36
32
  to: path.resolve(cwd, 'src', 'store.js'),
37
33
  });
34
+ toCopy.push({
35
+ from: path.resolve(__dirname, 'vite.config.js'),
36
+ to: path.resolve(cwd, 'vite.config.js'),
37
+ });
38
+ toCopy.push({
39
+ from: path.resolve(__dirname, 'global-components.d.ts'),
40
+ to: path.resolve(cwd, 'src', 'global-components.d.ts'),
41
+ });
42
+ toCopy.push({
43
+ from: path.resolve(__dirname, 'components', 'header.vue'),
44
+ to: path.resolve(cwd, 'src', 'components', 'header.vue'),
45
+ });
46
+ toCopy.push({
47
+ from: path.resolve(__dirname, 'components', 'sun-and-moon.vue'),
48
+ to: path.resolve(cwd, 'src', 'components', 'sun-and-moon.vue'),
49
+ });
50
+ toCopy.push({
51
+ from: path.resolve(__dirname, 'icons', 'sun.svg'),
52
+ to: path.resolve(cwd, 'src', 'static', 'icons', 'sun.svg'),
53
+ });
54
+ toCopy.push({
55
+ from: path.resolve(__dirname, 'icons', 'moon.svg'),
56
+ to: path.resolve(cwd, 'src', 'static', 'icons', 'moon.svg'),
57
+ });
58
+
38
59
 
39
60
  if (bundler) {
40
61
  toCopy.push({
@@ -33,7 +33,7 @@ module.exports = function (options) {
33
33
  });
34
34
  toCopy.push({
35
35
  content: generateHomePage(options),
36
- to: path.resolve(cwd, 'src', 'pages', 'home.vue')
36
+ to: path.resolve(cwd, 'src', 'pages', 'index.vue')
37
37
  });
38
38
  toCopy.push({
39
39
  content: generateRoot(options),
@@ -1,110 +1,56 @@
1
1
  const indent = require('../../utils/indent');
2
2
 
3
3
  module.exports = (options) => {
4
- const {
5
- name,
6
- template,
7
- } = options;
8
-
9
- let description = '';
10
- if (template === 'single-view' || template === 'blank') {
11
- description = `
12
- <p>Here is your blank ZMP app. Let's see what we have here.</p>
13
- `;
14
- }
15
- if (template === 'split-view') {
16
- description = `
17
- <p>This is an example of split view application layout, commonly used on tablets. The main approach of such kind of layout is that you can see different views at the same time.</p>
18
-
19
- <p>Each view may have different layout, different navbar type (dynamic, fixed or static) or without navbar.</p>
20
-
21
- <p>The fun thing is that you can easily control one view from another without any line of JavaScript just using "data-view" attribute on links.</p>
22
- `;
23
- }
24
- if (template === 'tabs') {
25
- description = `
26
- <p>This is an example of tabs-layout application. The main point of such tabbed layout is that each tab contains independent view with its own routing and navigation.</p>
27
-
28
- <p>Each tab/view may have different layout, different navbar type (dynamic, fixed or static) or without navbar like this tab.</p>
29
- `;
30
- }
4
+ const { name, template } = options;
31
5
 
32
6
  return indent(0, `
33
- <template>
34
- <zmp-page name="home">
35
- <!-- Top Navbar -->
36
- ${template === 'blank' ? `
37
- <zmp-navbar large>
38
- <zmp-nav-title>${name}</zmp-nav-title>
39
- <zmp-nav-title-large>${name}</zmp-nav-title-large>
40
- </zmp-navbar>
41
- `.trim() : `
42
- <zmp-navbar large :sliding="false">
43
- <zmp-nav-left>
44
- <zmp-link icon-ios="zmp:menu" icon-aurora="zmp:menu" icon-md="material:menu" panel-open="left"></zmp-link>
45
- </zmp-nav-left>
46
- <zmp-nav-title sliding>${name}</zmp-nav-title>
47
- <zmp-nav-right>
48
- <zmp-link icon-ios="zmp:menu" icon-aurora="zmp:menu" icon-md="material:menu" panel-open="right"></zmp-link>
49
- </zmp-nav-right>
50
- <zmp-nav-title-large>${name}</zmp-nav-title-large>
51
- </zmp-navbar>
52
- `.trim()}
53
- ${template !== 'tabs' ? `
54
- <!-- Toolbar-->
55
- <zmp-toolbar bottom>
56
- <zmp-link>Left Link</zmp-link>
57
- <zmp-link>Right Link</zmp-link>
58
- </zmp-toolbar>
59
-
60
- `.trim() : ''}
61
- <!-- Page content-->
62
- <zmp-block strong>
63
- ${description.trim()}
64
- </zmp-block>
65
- ${template !== 'blank' ? `
66
- <zmp-block-title>Navigation</zmp-block-title>
67
- <zmp-list>
68
- <zmp-list-item link="/about/" title="About"></zmp-list-item>
69
- <zmp-list-item link="/form/" title="Form"></zmp-list-item>
70
- </zmp-list>
71
-
72
- <zmp-block-title>Modals</zmp-block-title>
73
- <zmp-block strong>
74
- <zmp-row>
75
- <zmp-col width="50">
76
- <zmp-button fill raised popup-open="#my-popup">Popup</zmp-button>
77
- </zmp-col>
78
- <zmp-col width="50">
79
- <zmp-button fill raised login-screen-open="#my-login-screen">Login Screen</zmp-button>
80
- </zmp-col>
81
- </zmp-row>
82
- </zmp-block>
83
-
84
- <zmp-block-title>Panels</zmp-block-title>
85
- <zmp-block strong>
86
- <zmp-row>
87
- <zmp-col width="50">
88
- <zmp-button fill raised panel-open="left">Left Panel</zmp-button>
89
- </zmp-col>
90
- <zmp-col width="50">
91
- <zmp-button fill raised panel-open="right">Right Panel</zmp-button>
92
- </zmp-col>
93
- </zmp-row>
94
- </zmp-block>
95
-
96
- <zmp-list>
97
- <zmp-list-item
98
- title="Dynamic (Component) Route"
99
- link="/dynamic-route/blog/45/post/125/?foo=bar#about"
100
- ></zmp-list-item>
101
- <zmp-list-item
102
- title="Default Route (404)"
103
- link="/load-something-that-doesnt-exist/"
104
- ></zmp-list-item>
105
- </zmp-list>
106
- `.trim() : ''}
107
- </zmp-page>
108
- </template>
7
+ <template>
8
+ <zmp-page name="home" :theme-dark="darkMode">
9
+ <Header />
10
+ <zmp-box m="4">
11
+ <zmp-card inset title="Welcome to Zalo Mini App. Let's see what we have here.">
12
+ <p>
13
+ Recommended IDE Setup:
14
+ <a
15
+ href="https://code.visualstudio.com/"
16
+ target="_blank"
17
+ rel="nofollow"
18
+ >VSCode</a> +
19
+ <a
20
+ href="https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar"
21
+ target="_blank"
22
+ rel="nofollow"
23
+ >Volar</a>
24
+ </p>
25
+ <zmp-button @click="openDocs" fill responsive>Documentation</zmp-button>
26
+ </zmp-card>
27
+ </zmp-box>
28
+ <zmp-box m="4">
29
+ <zmp-card inset class="p-0">
30
+ <zmp-box flex justify-content="space-between" align-items="center">
31
+ <zmp-text bold class="mb-0">Example navigation</zmp-text>
32
+ <zmp-link href="/settings" transition="zmp-fade">
33
+ Settings
34
+ <zmp-icon zmp="zi-chevron-right" />
35
+ </zmp-link>
36
+ </zmp-box>
37
+ </zmp-card>
38
+ </zmp-box>
39
+ </zmp-page>
40
+ </template>
41
+
42
+ <script setup>
43
+ import { useStore } from 'zmp-vue';
44
+ import api from 'zmp-sdk';
45
+ import Header from "../components/header.vue";
46
+
47
+ const openDocs = () => {
48
+ api.openWebview({
49
+ url: 'https://mini.zalo.me'
50
+ });
51
+ };
52
+
53
+ const darkMode = useStore('darkMode');
54
+ </script>
109
55
  `).trim();
110
56
  };