├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .husky
├── commit-msg
├── post-merge
└── pre-commit
├── .npmrc
├── .scripts
├── check_pnpm.js
└── update_dependencies.sh
├── .sink.d.ts
├── .storybook
├── main.js
└── preview.js
├── .stylelintrc.js
├── .vscode
├── extensions.json
└── settings.json
├── LICENSE
├── README.md
├── README.zh.md
├── build-storybook.js
├── commitlint.config.js
├── deploy.config.js
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
└── favicon.ico
├── src
├── App.vue
├── assets
│ └── logo.png
├── components
│ ├── AboutPage.vue
│ ├── HomePage.vue
│ ├── TemplateIntroduction.stories.ts
│ ├── TemplateIntroduction.vue
│ └── WelcomeItem.vue
├── env.d.ts
├── main.ts
├── routes.ts
├── stores
│ └── counter.ts
├── stories
│ ├── Button.stories.js
│ ├── Button.vue
│ ├── Header.stories.js
│ ├── Header.vue
│ ├── Introduction.stories.mdx
│ ├── Page.stories.js
│ ├── Page.vue
│ ├── Themed.stories.ts
│ ├── ThemedExample.vue
│ ├── assets
│ │ ├── code-brackets.svg
│ │ ├── colors.svg
│ │ ├── comments.svg
│ │ ├── direction.svg
│ │ ├── flow.svg
│ │ ├── plugin.svg
│ │ ├── repo.svg
│ │ └── stackalt.svg
│ ├── button.css
│ ├── header.css
│ └── page.css
└── styles
│ └── main.less
├── tsconfig.json
├── vite.config.ts
└── windi.config.ts
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | !.storybook
4 | !.*.js
5 | !.*.ts
6 | !.scripts
7 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /** @type {import('eslint').Linter.Config} */
2 | module.exports = {
3 | extends: [
4 | 'standard-with-typescript',
5 | 'plugin:vue/vue3-recommended'
6 | ],
7 | // We have to explicit set the parser: https://stackoverflow.com/a/66525357
8 | parserOptions: {
9 | parser: '@typescript-eslint/parser'
10 | },
11 | // https://eslint.vuejs.org/user-guide/#compiler-macros-such-as-defineprops-and-defineemits-generate-no-undef-warnings
12 | env: {
13 | 'vue/setup-compiler-macros': true
14 | },
15 | overrides: [
16 | {
17 | files: ['*.ts', '*.tsx'],
18 | parserOptions: {
19 | project: ['./tsconfig.json']
20 | },
21 | rules: {
22 | // The core 'no-undef' rules does not work with type definitions
23 | 'no-undef': 'off'
24 | }
25 | },
26 | // storybook specific rules
27 | {
28 | files: ['**/**.stories.ts', '**/**.stories.tsx'],
29 | rules: {
30 | 'import/no-anonymous-default-export': 0,
31 | 'no-console': 0,
32 | '@typescript-eslint/consistent-type-assertions': 0
33 |
34 | }
35 | }
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | # Avoid triggering two build on PR
3 | # https://github.community/t/how-to-trigger-an-action-on-push-or-pull-request-but-not-both/16662/2
4 | on:
5 | push:
6 | branches:
7 | - main
8 | pull_request:
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build-and-prerelease:
14 | runs-on: macos-latest
15 | steps:
16 | - uses: actions/checkout@v2
17 | - uses: actions/setup-node@v2
18 | with:
19 | node-version: '14'
20 | - uses: pnpm/action-setup@v2.0.1
21 | with:
22 | version: 6.0.2
23 |
24 | - name: Install and Build 🔧
25 | run: |
26 | pnpm i
27 | pnpm run build
28 | pnpm run build-storybook
29 |
30 | - name: Deploy 🚀
31 | uses: JamesIves/github-pages-deploy-action@4.1.5
32 | with:
33 | branch: gh-pages # The branch the action should deploy to.
34 | folder: dist # The folder the action should deploy.
35 | git-config-name: 'github-actions[bot]'
36 | git-config-email: 'github-actions[bot]@users.noreply.github.com'
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | pnpx commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/post-merge:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | sh .scripts/update_dependencies.sh
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | pnpx lint-staged
5 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # Make storybook happy with its deps
2 | shamefully-hoist=true
3 |
--------------------------------------------------------------------------------
/.scripts/check_pnpm.js:
--------------------------------------------------------------------------------
1 | if (!/pnpm\.[cm]js$/.test(process.env.npm_execpath || '')) {
2 | console.warn(
3 | '\u001b[33mThis repository requires pnpm for scripts to work properly.\u001b[39m\n'
4 | )
5 | process.exit(1)
6 | }
7 |
--------------------------------------------------------------------------------
/.scripts/update_dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # MIT © Sindre Sorhus - sindresorhus.com
3 | # 当 git pull 的时候发现以来有更新的话,pnpm i 一下,参考链接:
4 | # https://gist.github.com/sindresorhus/7996717
5 | # https://gist.github.com/GianlucaGuarini/8001627
6 |
7 | # git hook to run a command after `git pull` if a specified file was changed
8 | # Run `chmod +x post-merge` to make it executable then put it into `.git/hooks/`.
9 |
10 | changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
11 |
12 | check_run() {
13 | echo "$changed_files" | grep -E --quiet "$1" && eval "$2"
14 | }
15 |
16 | # Example usage
17 | # In this example it's used to run `pnpm install` if package.json changed
18 | check_run "package.json|pnpm-lock.yaml" "pnpm install"
19 |
--------------------------------------------------------------------------------
/.sink.d.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/upupming/vue3-compact-template/9f9efecb82a15628be7a6801cc5c48e309a2ba54/.sink.d.ts
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const WindiCSS = require('vite-plugin-windicss').default
3 | const deployConfig = require('../deploy.config')
4 |
5 | module.exports = {
6 | stories: [
7 | '../src/**/*.stories.mdx',
8 | '../src/**/*.stories.@(js|jsx|ts|tsx)'
9 | ],
10 | addons: [
11 | '@storybook/addon-links',
12 | '@storybook/addon-essentials'
13 | ],
14 | framework: '@storybook/vue3',
15 | core: {
16 | builder: 'storybook-builder-vite'
17 | },
18 | async viteFinal (config, { configType }) {
19 | // customize the Vite config here
20 | config.resolve.alias['@/'] = `${path.resolve(__dirname, '../src')}/`
21 |
22 | config.plugins.push(WindiCSS())
23 |
24 | // solve cjs name export not able to be converted to esm problem
25 | // https://github.com/vitejs/vite/issues/813#issuecomment-691799104
26 | // https://github.com/eirslett/storybook-builder-vite/issues/132
27 | config.optimizeDeps = config.optimizeDeps || {}
28 | config.optimizeDeps.include = config.optimizeDeps.include || []
29 | config.optimizeDeps.include.push('synchronous-promise')
30 |
31 | // https://github.com/storybookjs/storybook/issues/10887#issuecomment-901109891
32 | config.resolve.dedupe = ['@storybook/client-api']
33 |
34 | config.base = `/${deployConfig.path}/${deployConfig.storybookFolder}/`
35 |
36 | // return the customized config
37 | return config
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | // https://stackoverflow.com/a/67001933
2 | import { app } from '@storybook/vue3'
3 | // CSS must be imported before .vue files to ensure that the styles defined in .vue files cam overwrite the default base styles
4 | // windicss layers
5 | import 'virtual:windi-base.css'
6 | import 'virtual:windi-components.css'
7 | // windicss utilities should be the last style import
8 | import 'virtual:windi-utilities.css'
9 | // windicss devtools support (dev only)
10 | import 'virtual:windi-devtools'
11 | import { createPinia } from 'pinia'
12 |
13 | export const parameters = {
14 | actions: { argTypesRegex: '^on[A-Z].*' },
15 | controls: {
16 | matchers: {
17 | color: /(background|color)$/i,
18 | date: /Date$/
19 | }
20 | }
21 | }
22 | const pinia = createPinia()
23 | app.use(pinia)
24 |
--------------------------------------------------------------------------------
/.stylelintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | 'stylelint-config-standard',
4 | './node_modules/prettier-stylelint/config.js',
5 | // https://www.npmjs.com/package/postcss-html
6 | 'stylelint-config-html',
7 | 'stylelint-config-recommended-vue',
8 | 'stylelint-config-recommended-less'
9 | ],
10 | customSyntax: 'postcss-less',
11 | rules: {
12 | 'less/no-duplicate-variables': null
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "coenraads.bracket-pair-colorizer",
4 | "johnsoncodehk.volar",
5 | "streetsidesoftware.code-spell-checker",
6 | "naumovs.color-highlight",
7 | "dbaeumer.vscode-eslint",
8 | "eamodio.gitlens",
9 | "wix.vscode-import-cost",
10 | "pkief.material-icon-theme",
11 | "esbenp.prettier-vscode",
12 | "yzhang.markdown-all-in-one",
13 | "davidanson.vscode-markdownlint",
14 | "stylelint.vscode-stylelint",
15 | "voorjaar.windicss-intellisense",
16 | // This plugin makes import { xxx } from 'xxx.vue' works in ts: https://github.com/johnsoncodehk/volar/issues/664
17 | "johnsoncodehk.vscode-typescript-vue-plugin"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use eslint to format js/ts files
3 | "editor.codeActionsOnSave": {
4 | "source.fixAll.eslint": true,
5 | "source.fixAll.stylelint": true
6 | },
7 | "editor.wordWrap": "on",
8 | // Use prettier to format files
9 | "editor.formatOnSave": true,
10 | // Since we use eslint to format js/ts files, so we have to disable prettier to avoid confilcts
11 | "[javascript]": {
12 | "editor.formatOnSave": false
13 | },
14 | "[javascriptreact]": {
15 | "editor.formatOnSave": false
16 | },
17 | "[typescript]": {
18 | "editor.formatOnSave": false
19 | },
20 | "[typescriptreact]": {
21 | "editor.formatOnSave": false
22 | },
23 | // Disable css built-in lint
24 | "css.validate": false,
25 | "scss.validate": false,
26 | "less.validate": false,
27 | "stylelint.enable": true,
28 | "stylelint.validate": ["css", "less", "html", "vue"],
29 | "[css]": {
30 | "editor.formatOnSave": false
31 | },
32 | "[less]": {
33 | "editor.formatOnSave": false
34 | },
35 | "[scss]": {
36 | "editor.formatOnSave": false
37 | },
38 | "[vue]": {
39 | "editor.formatOnSave": false
40 | },
41 | "editor.defaultFormatter": "esbenp.prettier-vscode",
42 | "editor.tabSize": 2,
43 | "files.insertFinalNewline": true,
44 | "cSpell.words": [
45 | "commitlint",
46 | "pinia",
47 | "pnpm",
48 | "stylelint",
49 | "unplugin",
50 | "vite",
51 | "vueuse",
52 | "windi",
53 | "windicss"
54 | ],
55 | "editor.detectIndentation": false,
56 | "[markdown]": {
57 | "editor.formatOnSave": false,
58 | "editor.tabSize": 4,
59 | "editor.defaultFormatter": "yzhang.markdown-all-in-one"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021-present upupming
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue3-compact-template
2 |
3 | English | [中文](README.zh.md)
4 |
5 | [](https://standardjs.com)
6 | [](https://conventionalcommits.org)
7 |
8 | ⚡️ A simple and compact vue 3 template with current cutting edge front end technologies.
9 |
10 | See the live demo at:
11 |
12 | - http://upupming.site/vue3-compact-template/
13 | - http://upupming.site/vue3-compact-template/storybook/
14 |
15 | ## Tech stack
16 |
17 | - Framework: [Vue 3](https://v3.vuejs.org/)
18 | - Package manager: [pnpm](https://github.com/pnpm/pnpm)
19 | - Build tool: [Vite 2](https://vitejs.dev/)
20 | - State management: [Pinia](https://pinia.esm.dev/)
21 | - Router: [Vue Router](https://next.router.vuejs.org/)
22 | - Utility first CSS framework: [WindiCSS](https://windicss.org/)
23 | - CSS preprocessor: [Less](https://lesscss.org/)
24 | - UI component explorer: [Storybook](https://github.com/storybookjs/storybook/)
25 | - Icons: [unplugin-icons](https://github.com/antfu/unplugin-icons)
26 | - ESLint rule: [eslint-config-standard-with-typescript](https://github.com/standard/eslint-config-standard-with-typescript)
27 | - Style linting: stylelint standard
28 | - commit convention: husky + commitlint
29 |
30 | ## Development
31 |
32 | ```bash
33 | # Development
34 | pnpm run dev
35 | # Run storybook
36 | pnpm run storybook
37 | ```
38 |
39 | ## Build
40 |
41 | ```bash
42 | pnpm run build
43 | pnpm run build-storybook
44 | ```
45 |
46 | After built, the `dist` folder will contain both the app and storybook build result, you can just serve them using `pnpm run serve`.
47 |
48 | - http://localhost:5000/vue3-compact-template/
49 | - http://localhost:5000/vue3-compact-template/storybook/
50 |
51 | ### Recommendations
52 |
53 | - Component library: [NaiveUI](https://www.naiveui.com/zh-CN/os-theme), [arco design](https://arco.design/), [Varlet](https://github.com/haoziqaq/varlet)
54 | - [VueUse](https://github.com/antfu/vueuse) - collection of useful composition APIs
55 | - [`@vueuse/head`](https://github.com/vueuse/head) - manipulate document head reactively
56 |
57 | ## References
58 |
59 | - https://github.com/antfu/vitesse
60 | - [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup)
61 |
--------------------------------------------------------------------------------
/README.zh.md:
--------------------------------------------------------------------------------
1 | # vue3-compact-template
2 |
3 | [English](README.md) | 中文
4 |
5 | [](https://standardjs.com)
6 | [](https://conventionalcommits.org)
7 |
8 | ⚡️ 一个包含了当前最新的前端技术的简单紧凑的 Vue 3 模板。
9 |
10 | 前往以下地址查看 Demo:
11 |
12 | - http://upupming.site/vue3-compact-template/
13 | - http://upupming.site/vue3-compact-template/storybook/
14 |
15 | ## 技术栈
16 |
17 | - 前端框架: [Vue 3](https://v3.vuejs.org/)
18 | - 包管理器: [pnpm](https://github.com/pnpm/pnpm)
19 | - 构建工具: [Vite 2](https://vitejs.dev/)
20 | - 状态管理: [Pinia](https://pinia.esm.dev/)
21 | - 路由: [Vue Router](https://next.router.vuejs.org/)
22 | - 功能类优先 CSS 框架: [WindiCSS](https://windicss.org/)
23 | - CSS 预编译器: [Less](https://lesscss.org/)
24 | - UI 组件浏览工具: [Storybook](https://github.com/storybookjs/storybook/)
25 | - 图标: [unplugin-icons](https://github.com/antfu/unplugin-icons)
26 | - ESLint 规则: [eslint-config-standard-with-typescript](https://github.com/standard/eslint-config-standard-with-typescript)
27 | - 样式规范: stylelint standard
28 | - commit 规范: husky + commitlint
29 |
30 | ## 本地开发
31 |
32 | ```bash
33 | # 开发
34 | pnpm run dev
35 | # 运行 storybook
36 | pnpm run storybook
37 | ```
38 |
39 | ## 构建
40 |
41 | ```bash
42 | pnpm run build
43 | pnpm run build-storybook
44 | ```
45 |
46 | 构建之后,`dist` 文件夹中会包含项目和 Storybook 的静态资源文件。你可以使用 `pnpm run serve` 使用本地服务器来 serve 这些静态资源。
47 |
48 | - http://localhost:5000/vue3-compact-template/
49 | - http://localhost:5000/vue3-compact-template/storybook/
50 |
51 | ### 推荐搭配
52 |
53 | - 组件库: [NaiveUI](https://www.naiveui.com/zh-CN/os-theme), [arco design](https://arco.design/), [Varlet](https://github.com/haoziqaq/varlet)
54 | - [VueUse](https://github.com/antfu/vueuse) - 一些有用的 composition API
55 | - [`@vueuse/head`](https://github.com/vueuse/head) - 响应式修改 `head`
56 |
57 | ## 参考链接
58 |
59 | - https://github.com/antfu/vitesse
60 | - [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup)
61 |
--------------------------------------------------------------------------------
/build-storybook.js:
--------------------------------------------------------------------------------
1 | const { spawn } = require('child_process')
2 | const deployConfig = require('./deploy.config')
3 |
4 | spawn(
5 | /^win/.test(process.platform) ? 'pnpx.cmd' : 'pnpx',
6 | [
7 | 'build-storybook',
8 | '-o', `dist/${deployConfig.storybookFolder}`
9 | ],
10 | { stdio: 'inherit' }
11 | )
12 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-angular']
3 | }
4 |
--------------------------------------------------------------------------------
/deploy.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | path: 'vue3-compact-template',
3 | storybookFolder: 'storybook'
4 | }
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | vue3-compact-template
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-compact-template",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "preinstall": "node ./.scripts/check_pnpm.js",
6 | "dev": "vite",
7 | "build": "vue-tsc --noEmit && vite build",
8 | "prepare": "husky install",
9 | "serve": "vite preview",
10 | "lint:eslint": "eslint --fix --ext .js,.jsx,.ts,.tsx,.vue .",
11 | "lint:stylelint": "stylelint --fix **/*.{css,less,html,vue}",
12 | "lint": "pnpm run lint:eslint && pnpm run lint:stylelint",
13 | "storybook": "start-storybook -p 6006",
14 | "build-storybook": "node build-storybook.js"
15 | },
16 | "dependencies": {
17 | "pinia": "^2.0.0",
18 | "vue": "^3.2.16",
19 | "vue-router": "4"
20 | },
21 | "lint-staged": {
22 | "*.{js,jsx,ts,tsx,mjs,mjsx,cjs,cjsx,vue}": [
23 | "eslint --fix --color"
24 | ],
25 | "*.{css,less,html,vue}": [
26 | "stylelint --fix"
27 | ]
28 | },
29 | "devDependencies": {
30 | "@babel/core": "^7.16.0",
31 | "@commitlint/cli": "^13.2.1",
32 | "@commitlint/config-angular": "^13.2.0",
33 | "@commitlint/prompt-cli": "^13.2.1",
34 | "@iconify-json/carbon": "^1.0.8",
35 | "@iconify-json/fluent": "^1.0.6",
36 | "@iconify-json/gg": "^1.0.1",
37 | "@iconify-json/mdi": "^1.0.7",
38 | "@iconify-json/simple-icons": "^1.0.7",
39 | "@storybook/addon-actions": "^6.4.0-beta.23",
40 | "@storybook/addon-essentials": "^6.4.0-beta.23",
41 | "@storybook/addon-links": "^6.4.0-beta.23",
42 | "@storybook/vue3": "^6.4.0-beta.23",
43 | "@types/node": "^16.11.6",
44 | "@typescript-eslint/eslint-plugin": "^4.33.0",
45 | "@vitejs/plugin-vue": "^1.9.3",
46 | "babel-loader": "^8.2.3",
47 | "eslint": "^7.32.0",
48 | "eslint-config-standard-with-typescript": "^21.0.1",
49 | "eslint-plugin-import": "^2.22.1",
50 | "eslint-plugin-node": "^11.1.0",
51 | "eslint-plugin-promise": "^5.0.0",
52 | "eslint-plugin-vue": "^8.0.3",
53 | "husky": "^7.0.2",
54 | "less": "^4.1.2",
55 | "lint-staged": "^11.2.2",
56 | "prettier-stylelint": "^0.4.2",
57 | "standard-version": "^9.3.1",
58 | "storybook-builder-vite": "^0.1.3",
59 | "stylelint": "^14.0.1",
60 | "stylelint-config-html": "^1.0.0",
61 | "stylelint-config-recommended": "^6.0.0",
62 | "stylelint-config-recommended-less": "^1.0.1",
63 | "stylelint-config-recommended-vue": "^1.0.0",
64 | "stylelint-config-standard": "^23.0.0",
65 | "stylelint-less": "^1.0.1",
66 | "tailwindcss-themeable": "^1.3.0",
67 | "typescript": "^4.4.4",
68 | "unplugin-icons": "^0.12.17",
69 | "vite": "^2.6.14",
70 | "vite-plugin-windicss": "^1.5.4",
71 | "vue-loader": "^16.8.2",
72 | "vue-tsc": "^0.3.0",
73 | "windicss": "^3.2.1"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/upupming/vue3-compact-template/9f9efecb82a15628be7a6801cc5c48e309a2ba54/public/favicon.ico
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
20 |
21 | vue3-compact-template
22 |
23 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
39 | Home
40 |
41 |
45 | About
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
93 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/upupming/vue3-compact-template/9f9efecb82a15628be7a6801cc5c48e309a2ba54/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/AboutPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/components/HomePage.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Documentation
18 |
19 |
20 | Vue’s
21 | official documentation
25 | provides you with all information you need to get started.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Tooling
34 |
35 |
36 | This project is served and bundled with
37 | Vite . The recommended IDE
41 | setup is VSCode +
45 | Volar . If you need to test
49 | your components and web pages, check out
50 | Cypress and
54 | Cypress Component Testing .
58 |
59 |
60 |
61 | More instructions are available in README.md
.
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Ecosystem
70 |
71 |
72 | Get official tools and libraries for your project:
73 | Vuex ,
77 | Vue Router ,
81 | Vue Test Utils , and
85 | Vue Dev Tools . If you need more
89 | resources, we suggest paying
90 | Awesome Vue
94 | a visit.
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | Community
103 |
104 |
105 | Got stuck? Ask your question on
106 | Vue Land , our official Discord server, or
110 | StackOverflow .
114 | You should also subscribe to
115 | our mailing list and follow the official
119 | @vuejs
123 | twitter account for latest news in the Vue world.
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | Support Vue
132 |
133 |
134 | As an independent project, Vue relies on community backing for its sustainability. You can help
135 | us by
136 | becoming a sponsor .
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/src/components/TemplateIntroduction.stories.ts:
--------------------------------------------------------------------------------
1 | import TemplateIntroduction, { TemplateIntroductionProps } from './TemplateIntroduction.vue'
2 | import { action } from '@storybook/addon-actions'
3 | import { Meta, Story } from '@storybook/vue3'
4 |
5 | export default {
6 | title: 'Components',
7 | component: TemplateIntroduction,
8 | argTypes: {
9 | msg: {
10 | // https://storybook.js.org/docs/react/essentials/controls#annotation
11 | control: {
12 | type: 'text'
13 | }
14 | }
15 | }
16 | } as Meta
17 |
18 | const Template: Story = (args) => ({
19 | components: { TemplateIntroduction },
20 | // https://github.com/storybookjs/storybook/discussions/11372#discussioncomment-32947
21 | methods: { update: action('update') },
22 | setup () {
23 | return { args }
24 | },
25 | template: ' '
26 | })
27 |
28 | export const TemplateIntroductionDemo = Template.bind({})
29 | TemplateIntroductionDemo.args = {
30 | msg: '⚡️ A simple and compact vue 3 template with current cutting edge front end technologies.'
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/TemplateIntroduction.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
23 |
24 |
25 |
29 |
33 | {{ msg }}
34 |
35 |
36 |
37 | Tech stack
38 |
39 |
85 |
86 |
See README.md
for more information.
87 |
88 |
89 |
94 | ref in component count is: {{ count }}
95 |
96 |
97 |
98 |
99 |
104 | ref in pinia store count is: {{ counter.count }}
105 |
106 |
107 |
108 | Edit
109 | components/TemplateIntroduction.vue
to test hot module replacement.
110 |
111 |
112 |
113 |
114 |
143 |
--------------------------------------------------------------------------------
/src/components/WelcomeItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
73 |
--------------------------------------------------------------------------------
/src/env.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import { DefineComponent } from 'vue'
3 | const component: DefineComponent<{}, {}, any>
4 | export default component
5 | }
6 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | // CSS must be imported before .vue files to ensure that the styles defined in .vue files cam overwrite the default base styles
2 | // windicss layers
3 | import 'virtual:windi-base.css'
4 | import 'virtual:windi-components.css'
5 | // your custom styles here
6 | import './styles/main.less'
7 | // windicss utilities should be the last style import
8 | import 'virtual:windi-utilities.css'
9 | // windicss devtools support (dev only)
10 | import 'virtual:windi-devtools'
11 |
12 | import { createApp } from 'vue'
13 | import { createPinia } from 'pinia'
14 | import { createRouter, createWebHashHistory } from 'vue-router'
15 | import App from './App.vue'
16 | import { routes } from './routes'
17 |
18 | const router = createRouter({
19 | // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
20 | history: createWebHashHistory(),
21 | routes
22 | })
23 |
24 | const app = createApp(App)
25 |
26 | const pinia = createPinia()
27 | app.use(pinia)
28 |
29 | app.use(router)
30 |
31 | app.mount('#app')
32 |
--------------------------------------------------------------------------------
/src/routes.ts:
--------------------------------------------------------------------------------
1 | import HomePage from '@/components/HomePage.vue'
2 | import AboutPage from '@/components/AboutPage.vue'
3 | export const routes = [
4 | { path: '/', component: HomePage },
5 | { path: '/about', component: AboutPage }
6 | ]
7 |
--------------------------------------------------------------------------------
/src/stores/counter.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia'
2 |
3 | export const useCounterStore = defineStore('counter', {
4 | state: () => {
5 | return { count: 0 }
6 | },
7 | // could also be defined as
8 | // state: () => ({ count: 0 })
9 | actions: {
10 | increment () {
11 | this.count++
12 | }
13 | }
14 | })
15 |
--------------------------------------------------------------------------------
/src/stories/Button.stories.js:
--------------------------------------------------------------------------------
1 | import MyButton from './Button.vue'
2 |
3 | // More on default export: https://storybook.js.org/docs/vue/writing-stories/introduction#default-export
4 | export default {
5 | title: 'Example/Button',
6 | component: MyButton,
7 | // More on argTypes: https://storybook.js.org/docs/vue/api/argtypes
8 | argTypes: {
9 | backgroundColor: { control: 'color' },
10 | onClick: {},
11 | size: {
12 | control: { type: 'select' },
13 | options: ['small', 'medium', 'large']
14 | }
15 | }
16 | }
17 |
18 | // More on component templates: https://storybook.js.org/docs/vue/writing-stories/introduction#using-args
19 | const Template = (args) => ({
20 | // Components used in your story `template` are defined in the `components` object
21 | components: { MyButton },
22 | // The story's `args` need to be mapped into the template through the `setup()` method
23 | setup () {
24 | return { args }
25 | },
26 | // And then the `args` are bound to your component with `v-bind="args"`
27 | template: ' '
28 | })
29 |
30 | export const Primary = Template.bind({})
31 | // More on args: https://storybook.js.org/docs/vue/writing-stories/args
32 | Primary.args = {
33 | primary: true,
34 | label: 'Button'
35 | }
36 |
37 | export const Secondary = Template.bind({})
38 | Secondary.args = {
39 | label: 'Button'
40 | }
41 |
42 | export const Large = Template.bind({})
43 | Large.args = {
44 | size: 'large',
45 | label: 'Button'
46 | }
47 |
48 | export const Small = Template.bind({})
49 | Small.args = {
50 | size: 'small',
51 | label: 'Button'
52 | }
53 |
--------------------------------------------------------------------------------
/src/stories/Button.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 | {{ label }}
9 |
10 |
11 |
12 |
60 |
--------------------------------------------------------------------------------
/src/stories/Header.stories.js:
--------------------------------------------------------------------------------
1 | import MyHeader from './Header.vue'
2 |
3 | export default {
4 | title: 'Example/Header',
5 | component: MyHeader
6 | }
7 |
8 | const Template = (args) => ({
9 | // Components used in your story `template` are defined in the `components` object
10 | components: { MyHeader },
11 | // The story's `args` need to be mapped into the template through the `setup()` method
12 | setup () {
13 | // Story args can be spread into the returned object
14 | return { ...args }
15 | },
16 | // Then, the spread values can be accessed directly in the template
17 | template: ' '
18 | })
19 |
20 | export const LoggedIn = Template.bind({})
21 | LoggedIn.args = {
22 | user: {}
23 | }
24 |
25 | export const LoggedOut = Template.bind({})
26 | LoggedOut.args = {
27 | user: null
28 | }
29 |
--------------------------------------------------------------------------------
/src/stories/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
15 |
19 |
23 |
27 |
28 |
29 |
Acme
30 |
31 |
32 |
38 |
44 |
51 |
52 |
53 |
54 |
55 |
56 |
74 |
--------------------------------------------------------------------------------
/src/stories/Introduction.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/addon-docs';
2 | import Code from './assets/code-brackets.svg';
3 | import Colors from './assets/colors.svg';
4 | import Comments from './assets/comments.svg';
5 | import Direction from './assets/direction.svg';
6 | import Flow from './assets/flow.svg';
7 | import Plugin from './assets/plugin.svg';
8 | import Repo from './assets/repo.svg';
9 | import StackAlt from './assets/stackalt.svg';
10 |
11 |
12 |
13 |
116 |
117 | # Welcome to Storybook
118 |
119 | Storybook helps you build UI components in isolation from your app's business logic, data, and context.
120 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA.
121 |
122 | Browse example stories now by navigating to them in the sidebar.
123 | View their code in the `src/stories` directory to learn how they work.
124 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages.
125 |
126 | Configure
127 |
128 |
174 |
175 | Learn
176 |
177 |
207 |
208 |
209 | Tip Edit the Markdown in{' '}
210 | src/stories/Introduction.stories.mdx
211 |
212 |
--------------------------------------------------------------------------------
/src/stories/Page.stories.js:
--------------------------------------------------------------------------------
1 | import MyPage from './Page.vue'
2 | import * as HeaderStories from './Header.stories'
3 |
4 | export default {
5 | title: 'Example/Page',
6 | component: MyPage
7 | }
8 |
9 | const Template = (args) => ({
10 | // Components used in your story `template` are defined in the `components` object
11 | components: { MyPage },
12 | // The story's `args` need to be mapped into the template through the `setup()` method
13 | setup () {
14 | // Story args can be mapped to keys in the returned object
15 | return { user: args.user }
16 | },
17 | // Then, those values can be accessed directly in the template
18 | template: ' '
19 | })
20 |
21 | export const LoggedIn = Template.bind({})
22 | LoggedIn.args = {
23 | // More on composing args: https://storybook.js.org/docs/vue/writing-stories/args#args-composition
24 | ...HeaderStories.LoggedIn.args
25 | }
26 |
27 | export const LoggedOut = Template.bind({})
28 | LoggedOut.args = {
29 | ...HeaderStories.LoggedOut.args
30 | }
31 |
--------------------------------------------------------------------------------
/src/stories/Page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 | Pages in Storybook
12 |
13 | We recommend building UIs with a
14 |
19 | component-driven
20 |
21 | process starting with atomic components and ending with pages.
22 |
23 |
24 | Render pages with mock data. This makes it easy to build and review page states without
25 | needing to navigate to them in your app. Here are some handy patterns for managing page data
26 | in Storybook:
27 |
28 |
29 |
30 | Use a higher-level connected component. Storybook helps you compose such data from the
31 | "args" of child component stories
32 |
33 |
34 | Assemble data in the page component from your services. You can mock these services out
35 | using Storybook.
36 |
37 |
38 |
39 | Get a guided tutorial on component-driven development at
40 | Storybook tutorials
45 | . Read more in the
46 | docs
51 | .
52 |
53 |
54 |
Tip
55 | Adjust the width of the canvas with the
56 |
62 |
66 |
71 |
72 |
73 | Viewports addon in the toolbar
74 |
75 |
76 |
77 |
78 |
79 |
97 |
--------------------------------------------------------------------------------
/src/stories/Themed.stories.ts:
--------------------------------------------------------------------------------
1 | import { Story, Meta } from '@storybook/vue3'
2 | import ThemedExample from './ThemedExample.vue'
3 |
4 | /**
5 | * https://www.youtube.com/watch?v=MAtaT8BZEAo&ab_channel=TailwindLabs
6 | * https://play.tailwindcss.com/YelhilBeHb
7 | */
8 | export default {
9 | title: 'Components'
10 | } as Meta
11 |
12 | export const Themed: Story = (args) => ({
13 | components: {
14 | ThemedExample
15 | },
16 | template: ' '
17 | })
18 |
--------------------------------------------------------------------------------
/src/stories/ThemedExample.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
16 |
17 | Ac euismod vel sit maecenas id pellentesque eu sed consectetur. Malesuada adipiscing sagittis vel nulla nec.
18 |
19 |
31 |
32 |
33 |
34 |
35 |
40 |
41 |
42 |
46 |
47 | Ac euismod vel sit maecenas id pellentesque eu sed consectetur. Malesuada adipiscing sagittis vel nulla nec.
48 |
49 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/stories/assets/code-brackets.svg:
--------------------------------------------------------------------------------
1 | illustration/code-brackets
--------------------------------------------------------------------------------
/src/stories/assets/colors.svg:
--------------------------------------------------------------------------------
1 | illustration/colors
--------------------------------------------------------------------------------
/src/stories/assets/comments.svg:
--------------------------------------------------------------------------------
1 | illustration/comments
--------------------------------------------------------------------------------
/src/stories/assets/direction.svg:
--------------------------------------------------------------------------------
1 | illustration/direction
--------------------------------------------------------------------------------
/src/stories/assets/flow.svg:
--------------------------------------------------------------------------------
1 | illustration/flow
--------------------------------------------------------------------------------
/src/stories/assets/plugin.svg:
--------------------------------------------------------------------------------
1 | illustration/plugin
--------------------------------------------------------------------------------
/src/stories/assets/repo.svg:
--------------------------------------------------------------------------------
1 | illustration/repo
--------------------------------------------------------------------------------
/src/stories/assets/stackalt.svg:
--------------------------------------------------------------------------------
1 | illustration/stackalt
--------------------------------------------------------------------------------
/src/stories/button.css:
--------------------------------------------------------------------------------
1 | .storybook-button {
2 | font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
3 | font-weight: 700;
4 | border: 0;
5 | border-radius: 3em;
6 | cursor: pointer;
7 | display: inline-block;
8 | line-height: 1;
9 | }
10 |
11 | /* stylelint-disable */
12 | .storybook-button--primary {
13 | color: white;
14 | background-color: #1ea7fd;
15 | }
16 |
17 | .storybook-button--secondary {
18 | color: #333;
19 | background-color: transparent;
20 | box-shadow: rgb(0 0 0 / 15%) 0 0 0 1px inset;
21 | }
22 |
23 | .storybook-button--small {
24 | font-size: 12px;
25 | padding: 10px 16px;
26 | }
27 |
28 | .storybook-button--medium {
29 | font-size: 14px;
30 | padding: 11px 20px;
31 | }
32 |
33 | .storybook-button--large {
34 | font-size: 16px;
35 | padding: 12px 24px;
36 | }
37 |
--------------------------------------------------------------------------------
/src/stories/header.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
3 | border-bottom: 1px solid rgb(0 0 0 / 10%);
4 | padding: 15px 20px;
5 | display: flex;
6 | align-items: center;
7 | justify-content: space-between;
8 | }
9 |
10 | svg {
11 | display: inline-block;
12 | vertical-align: top;
13 | }
14 |
15 | h1 {
16 | font-weight: 900;
17 | font-size: 20px;
18 | line-height: 1;
19 | margin: 6px 0 6px 10px;
20 | display: inline-block;
21 | vertical-align: top;
22 | }
23 |
24 | button + button {
25 | margin-left: 10px;
26 | }
27 |
--------------------------------------------------------------------------------
/src/stories/page.css:
--------------------------------------------------------------------------------
1 | section {
2 | font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
3 | font-size: 14px;
4 | line-height: 24px;
5 | padding: 48px 20px;
6 | margin: 0 auto;
7 | max-width: 600px;
8 | color: #333;
9 | }
10 |
11 | section h2 {
12 | font-weight: 900;
13 | font-size: 32px;
14 | line-height: 1;
15 | margin: 0 0 4px;
16 | display: inline-block;
17 | vertical-align: top;
18 | }
19 |
20 | section p {
21 | margin: 1em 0;
22 | }
23 |
24 | section a {
25 | text-decoration: none;
26 | color: #1ea7fd;
27 | }
28 |
29 | section ul {
30 | padding-left: 30px;
31 | margin: 1em 0;
32 | }
33 |
34 | section li {
35 | margin-bottom: 8px;
36 | }
37 |
38 | section .tip {
39 | display: inline-block;
40 | border-radius: 1em;
41 | font-size: 11px;
42 | line-height: 12px;
43 | font-weight: 700;
44 | background: #e7fdd8;
45 | color: #66bf3c;
46 | padding: 4px 12px;
47 | margin-right: 10px;
48 | vertical-align: top;
49 | }
50 |
51 | section .tip-wrapper {
52 | font-size: 13px;
53 | line-height: 20px;
54 | margin-top: 40px;
55 | margin-bottom: 40px;
56 | }
57 |
58 | section .tip-wrapper svg {
59 | display: inline-block;
60 | height: 12px;
61 | width: 12px;
62 | margin-right: 4px;
63 | vertical-align: top;
64 | margin-top: 3px;
65 | }
66 |
67 | section .tip-wrapper svg path {
68 | fill: #1ea7fd;
69 | }
70 |
--------------------------------------------------------------------------------
/src/styles/main.less:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | #app {
4 | height: 100%;
5 | margin: 0;
6 | padding: 0;
7 |
8 | @apply bg-gray-100;
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "useDefineForClassFields": true,
5 | "module": "esnext",
6 | "moduleResolution": "node",
7 | "strict": true,
8 | "jsx": "preserve",
9 | "sourceMap": true,
10 | "resolveJsonModule": true,
11 | "esModuleInterop": true,
12 | "lib": ["esnext", "dom"],
13 | "baseUrl": ".",
14 | "allowJs": true,
15 | "paths": {
16 | "@/*": ["src/*"],
17 | // disable react types as a work around for: https://github.com/storybookjs/storybook/pull/16629
18 | // https://github.com/Microsoft/TypeScript/issues/17042#issuecomment-327882577
19 | "react": [".sink.d.ts"]
20 | },
21 | "outDir": "out",
22 | "types": ["vite/client", "unplugin-icons/types/vue"],
23 | "skipLibCheck": true
24 | },
25 | "include": ["**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.vue"],
26 | "exclude": ["dist", "node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import path from 'path'
3 | import vue from '@vitejs/plugin-vue'
4 | import WindiCSS from 'vite-plugin-windicss'
5 | import deployConfig from './deploy.config.js'
6 | import Icons from 'unplugin-icons/vite'
7 |
8 | // https://vitejs.dev/config/
9 | export default defineConfig({
10 | resolve: {
11 | alias: {
12 | '@/': `${path.resolve(__dirname, 'src')}/`
13 | }
14 | },
15 | plugins: [
16 | vue(),
17 | WindiCSS(),
18 | Icons({
19 | autoInstall: true
20 | })
21 | ],
22 | base: `/${deployConfig.path}/`
23 | })
24 |
--------------------------------------------------------------------------------
/windi.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'windicss/helpers'
2 | import { themeable } from 'tailwindcss-themeable'
3 |
4 | export default defineConfig({
5 | theme: {
6 | extend: {
7 | }
8 | },
9 | variants: {
10 | extend: []
11 | },
12 | plugins: [themeable()]
13 | }
14 | )
15 |
--------------------------------------------------------------------------------