├── .gitignore ├── README.md ├── app.js ├── basic-components ├── app.js └── index.html ├── composition-api ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── Money.vue │ ├── assets │ │ └── logo.png │ ├── composables │ │ └── useRate.js │ ├── main.js │ └── store │ │ └── index.js └── vite.config.js ├── first-unit-test ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── Form.spec.js │ │ ├── Form.vue │ │ ├── HelloWorld.spec.js │ │ └── HelloWorld.vue │ ├── composables │ │ ├── useUser.js │ │ └── useUser.spec.js │ ├── main.js │ └── mocks │ │ └── handlers.js ├── test │ └── basic.test.js └── vite.config.js ├── index.html ├── options-api-to-composition-api ├── .browserslistrc ├── .env.development ├── .env.production ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── Landing.vue │ ├── components │ │ ├── base │ │ │ ├── BaseCheckbox.vue │ │ │ ├── BaseSmallListButton.vue │ │ │ └── BaseTextButton.vue │ │ ├── project │ │ │ ├── ProjectList.vue │ │ │ ├── ProjectListItem.vue │ │ │ └── ProjectSummaryLine.vue │ │ └── task │ │ │ ├── AddTaskInput.vue │ │ │ ├── TodoListItem.vue │ │ │ ├── TodoListItemMenu.vue │ │ │ └── TodoListItemMenuMove.vue │ ├── landing.js │ ├── main.js │ └── store │ │ ├── actions-types.js │ │ ├── index.js │ │ ├── modules │ │ ├── application.js │ │ └── project.js │ │ ├── mutation-types.js │ │ └── plugins │ │ └── localStorage.js └── vue.config.js ├── router ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html └── src │ ├── App.vue │ ├── assets │ └── logo.png │ ├── components │ └── ArticleList.vue │ ├── data.js │ ├── main.js │ └── pages │ ├── AboutPage.vue │ ├── ArticlePage.vue │ ├── ArticlePage │ ├── ArticleAuthor.vue │ └── ArticleCommentList.vue │ ├── ArticlesByTagPage.vue │ ├── HomePage.vue │ ├── LoginPage.vue │ └── NotFoundPage.vue ├── single-file-components ├── .browserslistrc ├── .env.development ├── .env.production ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── Landing.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── AddTaskInput.vue │ │ ├── BaseCheckbox.vue │ │ ├── HelloWorld.vue │ │ └── TodoListItem.vue │ ├── landing.js │ └── main.js └── vue.config.js ├── the-game ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── components │ │ └── Counter.vue │ ├── main.js │ ├── router.js │ ├── stores │ │ └── counter.js │ └── views │ │ ├── Game.vue │ │ └── HallOfFame.vue └── vite.config.js ├── todo-firebase ├── .gitignore ├── README.md ├── firebase.json ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── Landing.vue │ ├── components │ │ ├── base │ │ │ ├── BaseCheckbox.vue │ │ │ ├── BaseSmallListButton.vue │ │ │ └── BaseTextButton.vue │ │ ├── project │ │ │ ├── ProjectAdd.vue │ │ │ ├── ProjectList.vue │ │ │ ├── ProjectListItem.vue │ │ │ └── ProjectSummaryLine.vue │ │ ├── task │ │ │ ├── AddTaskInput.vue │ │ │ ├── TodoListItem.vue │ │ │ ├── TodoListItemMenu.vue │ │ │ └── TodoListItemMenuMove.vue │ │ └── user │ │ │ └── UserProfile.vue │ ├── composables │ │ └── useCredentials.js │ ├── firebase │ │ ├── project.js │ │ └── user.js │ ├── index.css │ ├── landing.js │ ├── main.js │ ├── pages │ │ ├── LoginPage.vue │ │ ├── ProjectPage.vue │ │ └── SignupPage.vue │ ├── router │ │ └── index.js │ └── store │ │ ├── actions-types.js │ │ ├── index.js │ │ ├── modules │ │ ├── application.js │ │ └── project.js │ │ ├── mutation-types.js │ │ └── plugins │ │ └── localStorage.js ├── tailwind.config.js └── vite.config.js ├── transitions-animations ├── transition-group │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.vue │ │ ├── components │ │ │ └── ListItem.vue │ │ └── main.js │ └── vite.config.js ├── transition │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.vue │ │ ├── Fade.vue │ │ ├── FadeTransition.vue │ │ ├── Heart.vue │ │ ├── TransitionBetween.vue │ │ ├── main.css │ │ └── main.js │ └── vite.config.js └── transitions-animations.html └── vuex ├── .browserslistrc ├── .env.development ├── .env.production ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── Landing.vue ├── components │ ├── base │ │ ├── BaseCheckbox.vue │ │ ├── BaseSmallListButton.vue │ │ └── BaseTextButton.vue │ ├── project │ │ ├── ProjectList.vue │ │ ├── ProjectListItem.vue │ │ └── ProjectSummaryLine.vue │ └── task │ │ ├── AddTaskInput.vue │ │ ├── TodoListItem.vue │ │ ├── TodoListItemMenu.vue │ │ └── TodoListItemMenuMove.vue ├── landing.js ├── main.js └── store │ ├── actions-types.js │ ├── index.js │ ├── modules │ ├── application.js │ └── project.js │ ├── mutation-types.js │ └── plugins │ └── localStorage.js └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

Piotr Jura - Udemy Instructor

3 |

Piotr Jura Udemy Courses

4 |

Fado Code Camp

5 |
6 | 7 |

8 | High-quality, comprehensive courses for web developers. 9 |

10 | 11 |

12 | About the Instructor · 13 | Courses · 14 | Contact & Links · 15 | This Course Resources 16 |

17 |
18 | 19 | ## About the Instructor 20 | 21 | I am Piotr Jura, a seasoned web developer and a passionate Udemy instructor. With years of experience in JavaScript, TypeScript, Node, PHP, MySQL, Vue, React, and more, I bring practical, real-world knowledge to my students. 22 | 23 | ## Courses 24 | 25 | - [Master Nuxt 3 - Full-Stack Complete Guide](https://www.udemy.com/course/master-nuxt-full-stack-complete-guide/?referralCode=4EBA58BFBD39A31A9BE9) 26 | - [Symfony 6 Framework Hands-On 2023](https://www.udemy.com/course/symfony-framework-hands-on/?referralCode=6750F64C057515A5F787) 27 | - [Vue 3 Mastery: Firebase & More - Learn by Doing!](https://www.udemy.com/course/vuejs-course/?referralCode=26DAD96DAB47B4602DA3) 28 | - [Master NestJS - Node.js Framework 2023](https://www.udemy.com/course/master-nestjs-the-javascript-nodejs-framework/?referralCode=C8A3F83982053A5E44C0) 29 | - [Master Laravel with GraphQL, Vue.js, and Tailwind](https://www.udemy.com/course/master-laravel-with-graphql-vuejs-and-tailwind/?referralCode=CE3B5297B3614EFA884A) 30 | - [Master Laravel, Vue 3 & Inertia Full Stack 2023](https://www.udemy.com/course/master-laravel-6-with-vuejs-fullstack-development/?referralCode=4A6CED7AA1583CB709D6) 31 | - [Master Laravel 10 for Beginners & Intermediate 2023](https://www.udemy.com/course/laravel-beginner-fundamentals/?referralCode=E86A873AC47FB438D79C) 32 | - [Symfony API Platform with React Full Stack Masterclass](https://www.udemy.com/course/symfony-api-platform-reactjs-full-stack-masterclass/?referralCode=D2C29D1C641BB0CDBCD4) 33 | 34 | ## Contact and Links 35 | 36 | - **Blog:** [Fado Code Camp](https://fadocodecamp.com/) 37 | - **LinkedIn:** [Follow Me on LinkedIn](https://www.linkedin.com/in/piotr-j-24250b257/) 38 | - **GitHub:** You are here! Give me a follow! 39 | - **Twitter:** [@piotr_jura](https://twitter.com/piotr_jura) 40 | 41 | ## Course Resources 42 | 43 | Coming up! 44 | 45 | --- 46 | 47 |

48 | Explore, Learn, and Grow with My Comprehensive Web Development Courses! 49 |

50 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | let nextTaskId = 100; 2 | 3 | const app = Vue.createApp({ 4 | data() { 5 | return { 6 | onlyPending: false, 7 | tasks: [{ 8 | id: 1, 9 | description: 'Buy food for the dog', 10 | priority: false, 11 | done: false 12 | }, 13 | { 14 | id: 2, 15 | description: 'Pay the bills', 16 | priority: true, 17 | done: false 18 | }, 19 | { 20 | id: 3, 21 | description: 'Buy some computer games', 22 | priority: false, 23 | done: false 24 | }, 25 | { 26 | id: 4, 27 | description: 'Go to the gym', 28 | priority: false, 29 | done: false 30 | }] 31 | } 32 | }, 33 | computed: { 34 | displayedTasks() { 35 | return [...this.tasks].sort( 36 | (a, b) => Number(b.priority) - Number(a.priority) 37 | ) 38 | .filter( 39 | task => !this.onlyPending || !task.done 40 | ); 41 | } 42 | }, 43 | methods: { 44 | taskAdded(task) { 45 | this.tasks.push({ 46 | id: nextTaskId++, 47 | description: task, 48 | done: false, 49 | priority: false 50 | }); 51 | } 52 | } 53 | }); 54 | 55 | app.component('todo-list-item', { 56 | props: { 57 | task: { 58 | type: Object, 59 | required: true, 60 | // validator(value) { 61 | // return "Okay" === value; 62 | // } 63 | }, 64 | done: Boolean, 65 | priority: Boolean 66 | // id: { 67 | // required: false, 68 | // type: Number, 69 | // validator(value) { 70 | // return value >= 1 && value <= 100; 71 | // }, 72 | // // default() { 73 | // // return []; 74 | // // } 75 | // } 76 | }, 77 | emits: ['update:done', 'update:priority'], 78 | template: `
81 |
{{task.description}}
82 |
83 | Done 86 | Prioritized 89 |
90 |
91 | 92 | ` 93 | }); 94 | 95 | app.component('add-task-input', { 96 | emits: ['added'], 97 | data() { 98 | return { 99 | task: '' 100 | } 101 | }, 102 | methods: { 103 | add() { 104 | this.$emit('added', this.task); 105 | this.task = ''; 106 | } 107 | }, 108 | template: `` 113 | }); 114 | 115 | app.component('base-checkbox', { 116 | props: { 117 | modelValue: { 118 | type: Boolean, 119 | default: false 120 | }, 121 | }, 122 | emits: ['update:modelValue'], 123 | methods: { 124 | onChange() { 125 | this.$emit( 126 | 'update:modelValue', !this.modelValue 127 | ); 128 | } 129 | }, 130 | template: `
131 | 135 | 136 |
` 137 | }); 138 | 139 | app.mount('#app'); -------------------------------------------------------------------------------- /basic-components/app.js: -------------------------------------------------------------------------------- 1 | let nextTaskId = 100; 2 | 3 | const app = Vue.createApp({ 4 | data() { 5 | return { 6 | onlyPending: false, 7 | tasks: [{ 8 | id: 1, 9 | description: 'Buy food for the dog', 10 | priority: false, 11 | done: false 12 | }, 13 | { 14 | id: 2, 15 | description: 'Pay the bills', 16 | priority: true, 17 | done: false 18 | }, 19 | { 20 | id: 3, 21 | description: 'Buy some computer games', 22 | priority: false, 23 | done: false 24 | }, 25 | { 26 | id: 4, 27 | description: 'Go to the gym', 28 | priority: false, 29 | done: false 30 | }] 31 | } 32 | }, 33 | computed: { 34 | displayedTasks() { 35 | return [...this.tasks].sort( 36 | (a, b) => Number(b.priority) - Number(a.priority) 37 | ) 38 | .filter( 39 | task => !this.onlyPending || !task.done 40 | ); 41 | } 42 | }, 43 | methods: { 44 | taskAdded(task) { 45 | this.tasks.push({ 46 | id: nextTaskId++, 47 | description: task, 48 | done: false, 49 | priority: false 50 | }); 51 | } 52 | } 53 | }); 54 | 55 | app.component('todo-list-item', { 56 | props: { 57 | task: { 58 | type: Object, 59 | required: true, 60 | // validator(value) { 61 | // return "Okay" === value; 62 | // } 63 | }, 64 | done: Boolean, 65 | priority: Boolean 66 | // id: { 67 | // required: false, 68 | // type: Number, 69 | // validator(value) { 70 | // return value >= 1 && value <= 100; 71 | // }, 72 | // // default() { 73 | // // return []; 74 | // // } 75 | // } 76 | }, 77 | emits: ['update:done', 'update:priority'], 78 | template: `
81 |
{{task.description}}
82 |
83 | Done 86 | Prioritized 89 |
90 |
` 91 | }); 92 | 93 | app.component('add-task-input', { 94 | emits: ['added'], 95 | data() { 96 | return { 97 | task: '' 98 | } 99 | }, 100 | methods: { 101 | add() { 102 | this.$emit('added', this.task); 103 | this.task = ''; 104 | } 105 | }, 106 | mounted() { 107 | this.$refs.input.focus(); 108 | }, 109 | template: `` 115 | }); 116 | 117 | app.component('base-checkbox', { 118 | props: { 119 | modelValue: { 120 | type: Boolean, 121 | default: false 122 | }, 123 | }, 124 | emits: ['update:modelValue'], 125 | methods: { 126 | onChange() { 127 | this.$emit( 128 | 'update:modelValue', !this.modelValue 129 | ); 130 | } 131 | }, 132 | template: `
133 | 137 | 138 |
` 139 | }); 140 | 141 | app.mount('#app'); -------------------------------------------------------------------------------- /basic-components/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | Vue 3 Components 10 | 11 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | Only pending tasks 23 | 24 |
25 |
26 | 29 | 30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /composition-api/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local -------------------------------------------------------------------------------- /composition-api/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /composition-api/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "composition-api", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "composition-api", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "vue": "^3.2.25", 12 | "vuex": "^4.0.2" 13 | }, 14 | "devDependencies": { 15 | "@vitejs/plugin-vue": "^2.0.0", 16 | "vite": "^2.7.2" 17 | } 18 | }, 19 | "node_modules/@babel/parser": { 20 | "version": "7.16.6", 21 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", 22 | "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", 23 | "bin": { 24 | "parser": "bin/babel-parser.js" 25 | }, 26 | "engines": { 27 | "node": ">=6.0.0" 28 | } 29 | }, 30 | "node_modules/@vitejs/plugin-vue": { 31 | "version": "2.0.1", 32 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.0.1.tgz", 33 | "integrity": "sha512-wtdMnGVvys9K8tg+DxowU1ytTrdVveXr3LzdhaKakysgGXyrsfaeds2cDywtvujEASjWOwWL/OgWM+qoeM8Plg==", 34 | "dev": true, 35 | "engines": { 36 | "node": ">=12.0.0" 37 | }, 38 | "peerDependencies": { 39 | "vite": "^2.5.10", 40 | "vue": "^3.2.25" 41 | } 42 | }, 43 | "node_modules/@vue/compiler-core": { 44 | "version": "3.2.26", 45 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.26.tgz", 46 | "integrity": "sha512-N5XNBobZbaASdzY9Lga2D9Lul5vdCIOXvUMd6ThcN8zgqQhPKfCV+wfAJNNJKQkSHudnYRO2gEB+lp0iN3g2Tw==", 47 | "dependencies": { 48 | "@babel/parser": "^7.16.4", 49 | "@vue/shared": "3.2.26", 50 | "estree-walker": "^2.0.2", 51 | "source-map": "^0.6.1" 52 | } 53 | }, 54 | "node_modules/@vue/compiler-dom": { 55 | "version": "3.2.26", 56 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.26.tgz", 57 | "integrity": "sha512-smBfaOW6mQDxcT3p9TKT6mE22vjxjJL50GFVJiI0chXYGU/xzC05QRGrW3HHVuJrmLTLx5zBhsZ2dIATERbarg==", 58 | "dependencies": { 59 | "@vue/compiler-core": "3.2.26", 60 | "@vue/shared": "3.2.26" 61 | } 62 | }, 63 | "node_modules/@vue/compiler-sfc": { 64 | "version": "3.2.26", 65 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.26.tgz", 66 | "integrity": "sha512-ePpnfktV90UcLdsDQUh2JdiTuhV0Skv2iYXxfNMOK/F3Q+2BO0AulcVcfoksOpTJGmhhfosWfMyEaEf0UaWpIw==", 67 | "dependencies": { 68 | "@babel/parser": "^7.16.4", 69 | "@vue/compiler-core": "3.2.26", 70 | "@vue/compiler-dom": "3.2.26", 71 | "@vue/compiler-ssr": "3.2.26", 72 | "@vue/reactivity-transform": "3.2.26", 73 | "@vue/shared": "3.2.26", 74 | "estree-walker": "^2.0.2", 75 | "magic-string": "^0.25.7", 76 | "postcss": "^8.1.10", 77 | "source-map": "^0.6.1" 78 | } 79 | }, 80 | "node_modules/@vue/compiler-ssr": { 81 | "version": "3.2.26", 82 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.26.tgz", 83 | "integrity": "sha512-2mywLX0ODc4Zn8qBoA2PDCsLEZfpUGZcyoFRLSOjyGGK6wDy2/5kyDOWtf0S0UvtoyVq95OTSGIALjZ4k2q/ag==", 84 | "dependencies": { 85 | "@vue/compiler-dom": "3.2.26", 86 | "@vue/shared": "3.2.26" 87 | } 88 | }, 89 | "node_modules/@vue/devtools-api": { 90 | "version": "6.0.0-beta.21.1", 91 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.21.1.tgz", 92 | "integrity": "sha512-FqC4s3pm35qGVeXRGOjTsRzlkJjrBLriDS9YXbflHLsfA9FrcKzIyWnLXoNm+/7930E8rRakXuAc2QkC50swAw==" 93 | }, 94 | "node_modules/@vue/reactivity": { 95 | "version": "3.2.26", 96 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.26.tgz", 97 | "integrity": "sha512-h38bxCZLW6oFJVDlCcAiUKFnXI8xP8d+eO0pcDxx+7dQfSPje2AO6M9S9QO6MrxQB7fGP0DH0dYQ8ksf6hrXKQ==", 98 | "dependencies": { 99 | "@vue/shared": "3.2.26" 100 | } 101 | }, 102 | "node_modules/@vue/reactivity-transform": { 103 | "version": "3.2.26", 104 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.26.tgz", 105 | "integrity": "sha512-XKMyuCmzNA7nvFlYhdKwD78rcnmPb7q46uoR00zkX6yZrUmcCQ5OikiwUEVbvNhL5hBJuvbSO95jB5zkUon+eQ==", 106 | "dependencies": { 107 | "@babel/parser": "^7.16.4", 108 | "@vue/compiler-core": "3.2.26", 109 | "@vue/shared": "3.2.26", 110 | "estree-walker": "^2.0.2", 111 | "magic-string": "^0.25.7" 112 | } 113 | }, 114 | "node_modules/@vue/runtime-core": { 115 | "version": "3.2.26", 116 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.26.tgz", 117 | "integrity": "sha512-BcYi7qZ9Nn+CJDJrHQ6Zsmxei2hDW0L6AB4vPvUQGBm2fZyC0GXd/4nVbyA2ubmuhctD5RbYY8L+5GUJszv9mQ==", 118 | "dependencies": { 119 | "@vue/reactivity": "3.2.26", 120 | "@vue/shared": "3.2.26" 121 | } 122 | }, 123 | "node_modules/@vue/runtime-dom": { 124 | "version": "3.2.26", 125 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.26.tgz", 126 | "integrity": "sha512-dY56UIiZI+gjc4e8JQBwAifljyexfVCkIAu/WX8snh8vSOt/gMSEGwPRcl2UpYpBYeyExV8WCbgvwWRNt9cHhQ==", 127 | "dependencies": { 128 | "@vue/runtime-core": "3.2.26", 129 | "@vue/shared": "3.2.26", 130 | "csstype": "^2.6.8" 131 | } 132 | }, 133 | "node_modules/@vue/server-renderer": { 134 | "version": "3.2.26", 135 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.26.tgz", 136 | "integrity": "sha512-Jp5SggDUvvUYSBIvYEhy76t4nr1vapY/FIFloWmQzn7UxqaHrrBpbxrqPcTrSgGrcaglj0VBp22BKJNre4aA1w==", 137 | "dependencies": { 138 | "@vue/compiler-ssr": "3.2.26", 139 | "@vue/shared": "3.2.26" 140 | }, 141 | "peerDependencies": { 142 | "vue": "3.2.26" 143 | } 144 | }, 145 | "node_modules/@vue/shared": { 146 | "version": "3.2.26", 147 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.26.tgz", 148 | "integrity": "sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==" 149 | }, 150 | "node_modules/csstype": { 151 | "version": "2.6.19", 152 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", 153 | "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==" 154 | }, 155 | "node_modules/esbuild": { 156 | "version": "0.13.15", 157 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz", 158 | "integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==", 159 | "dev": true, 160 | "hasInstallScript": true, 161 | "bin": { 162 | "esbuild": "bin/esbuild" 163 | }, 164 | "optionalDependencies": { 165 | "esbuild-android-arm64": "0.13.15", 166 | "esbuild-darwin-64": "0.13.15", 167 | "esbuild-darwin-arm64": "0.13.15", 168 | "esbuild-freebsd-64": "0.13.15", 169 | "esbuild-freebsd-arm64": "0.13.15", 170 | "esbuild-linux-32": "0.13.15", 171 | "esbuild-linux-64": "0.13.15", 172 | "esbuild-linux-arm": "0.13.15", 173 | "esbuild-linux-arm64": "0.13.15", 174 | "esbuild-linux-mips64le": "0.13.15", 175 | "esbuild-linux-ppc64le": "0.13.15", 176 | "esbuild-netbsd-64": "0.13.15", 177 | "esbuild-openbsd-64": "0.13.15", 178 | "esbuild-sunos-64": "0.13.15", 179 | "esbuild-windows-32": "0.13.15", 180 | "esbuild-windows-64": "0.13.15", 181 | "esbuild-windows-arm64": "0.13.15" 182 | } 183 | }, 184 | "node_modules/esbuild-android-arm64": { 185 | "version": "0.13.15", 186 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz", 187 | "integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==", 188 | "cpu": [ 189 | "arm64" 190 | ], 191 | "dev": true, 192 | "optional": true, 193 | "os": [ 194 | "android" 195 | ] 196 | }, 197 | "node_modules/esbuild-darwin-64": { 198 | "version": "0.13.15", 199 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz", 200 | "integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==", 201 | "cpu": [ 202 | "x64" 203 | ], 204 | "dev": true, 205 | "optional": true, 206 | "os": [ 207 | "darwin" 208 | ] 209 | }, 210 | "node_modules/esbuild-darwin-arm64": { 211 | "version": "0.13.15", 212 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz", 213 | "integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==", 214 | "cpu": [ 215 | "arm64" 216 | ], 217 | "dev": true, 218 | "optional": true, 219 | "os": [ 220 | "darwin" 221 | ] 222 | }, 223 | "node_modules/esbuild-freebsd-64": { 224 | "version": "0.13.15", 225 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz", 226 | "integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==", 227 | "cpu": [ 228 | "x64" 229 | ], 230 | "dev": true, 231 | "optional": true, 232 | "os": [ 233 | "freebsd" 234 | ] 235 | }, 236 | "node_modules/esbuild-freebsd-arm64": { 237 | "version": "0.13.15", 238 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz", 239 | "integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==", 240 | "cpu": [ 241 | "arm64" 242 | ], 243 | "dev": true, 244 | "optional": true, 245 | "os": [ 246 | "freebsd" 247 | ] 248 | }, 249 | "node_modules/esbuild-linux-32": { 250 | "version": "0.13.15", 251 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz", 252 | "integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==", 253 | "cpu": [ 254 | "ia32" 255 | ], 256 | "dev": true, 257 | "optional": true, 258 | "os": [ 259 | "linux" 260 | ] 261 | }, 262 | "node_modules/esbuild-linux-64": { 263 | "version": "0.13.15", 264 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz", 265 | "integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==", 266 | "cpu": [ 267 | "x64" 268 | ], 269 | "dev": true, 270 | "optional": true, 271 | "os": [ 272 | "linux" 273 | ] 274 | }, 275 | "node_modules/esbuild-linux-arm": { 276 | "version": "0.13.15", 277 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz", 278 | "integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==", 279 | "cpu": [ 280 | "arm" 281 | ], 282 | "dev": true, 283 | "optional": true, 284 | "os": [ 285 | "linux" 286 | ] 287 | }, 288 | "node_modules/esbuild-linux-arm64": { 289 | "version": "0.13.15", 290 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz", 291 | "integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==", 292 | "cpu": [ 293 | "arm64" 294 | ], 295 | "dev": true, 296 | "optional": true, 297 | "os": [ 298 | "linux" 299 | ] 300 | }, 301 | "node_modules/esbuild-linux-mips64le": { 302 | "version": "0.13.15", 303 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz", 304 | "integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==", 305 | "cpu": [ 306 | "mips64el" 307 | ], 308 | "dev": true, 309 | "optional": true, 310 | "os": [ 311 | "linux" 312 | ] 313 | }, 314 | "node_modules/esbuild-linux-ppc64le": { 315 | "version": "0.13.15", 316 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz", 317 | "integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==", 318 | "cpu": [ 319 | "ppc64" 320 | ], 321 | "dev": true, 322 | "optional": true, 323 | "os": [ 324 | "linux" 325 | ] 326 | }, 327 | "node_modules/esbuild-netbsd-64": { 328 | "version": "0.13.15", 329 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz", 330 | "integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==", 331 | "cpu": [ 332 | "x64" 333 | ], 334 | "dev": true, 335 | "optional": true, 336 | "os": [ 337 | "netbsd" 338 | ] 339 | }, 340 | "node_modules/esbuild-openbsd-64": { 341 | "version": "0.13.15", 342 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz", 343 | "integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==", 344 | "cpu": [ 345 | "x64" 346 | ], 347 | "dev": true, 348 | "optional": true, 349 | "os": [ 350 | "openbsd" 351 | ] 352 | }, 353 | "node_modules/esbuild-sunos-64": { 354 | "version": "0.13.15", 355 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz", 356 | "integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==", 357 | "cpu": [ 358 | "x64" 359 | ], 360 | "dev": true, 361 | "optional": true, 362 | "os": [ 363 | "sunos" 364 | ] 365 | }, 366 | "node_modules/esbuild-windows-32": { 367 | "version": "0.13.15", 368 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz", 369 | "integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==", 370 | "cpu": [ 371 | "ia32" 372 | ], 373 | "dev": true, 374 | "optional": true, 375 | "os": [ 376 | "win32" 377 | ] 378 | }, 379 | "node_modules/esbuild-windows-64": { 380 | "version": "0.13.15", 381 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz", 382 | "integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==", 383 | "cpu": [ 384 | "x64" 385 | ], 386 | "dev": true, 387 | "optional": true, 388 | "os": [ 389 | "win32" 390 | ] 391 | }, 392 | "node_modules/esbuild-windows-arm64": { 393 | "version": "0.13.15", 394 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz", 395 | "integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==", 396 | "cpu": [ 397 | "arm64" 398 | ], 399 | "dev": true, 400 | "optional": true, 401 | "os": [ 402 | "win32" 403 | ] 404 | }, 405 | "node_modules/estree-walker": { 406 | "version": "2.0.2", 407 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 408 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 409 | }, 410 | "node_modules/fsevents": { 411 | "version": "2.3.2", 412 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 413 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 414 | "dev": true, 415 | "hasInstallScript": true, 416 | "optional": true, 417 | "os": [ 418 | "darwin" 419 | ], 420 | "engines": { 421 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 422 | } 423 | }, 424 | "node_modules/function-bind": { 425 | "version": "1.1.1", 426 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 427 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 428 | "dev": true 429 | }, 430 | "node_modules/has": { 431 | "version": "1.0.3", 432 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 433 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 434 | "dev": true, 435 | "dependencies": { 436 | "function-bind": "^1.1.1" 437 | }, 438 | "engines": { 439 | "node": ">= 0.4.0" 440 | } 441 | }, 442 | "node_modules/is-core-module": { 443 | "version": "2.8.0", 444 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", 445 | "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", 446 | "dev": true, 447 | "dependencies": { 448 | "has": "^1.0.3" 449 | }, 450 | "funding": { 451 | "url": "https://github.com/sponsors/ljharb" 452 | } 453 | }, 454 | "node_modules/magic-string": { 455 | "version": "0.25.7", 456 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", 457 | "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", 458 | "dependencies": { 459 | "sourcemap-codec": "^1.4.4" 460 | } 461 | }, 462 | "node_modules/nanoid": { 463 | "version": "3.1.30", 464 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", 465 | "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", 466 | "bin": { 467 | "nanoid": "bin/nanoid.cjs" 468 | }, 469 | "engines": { 470 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 471 | } 472 | }, 473 | "node_modules/path-parse": { 474 | "version": "1.0.7", 475 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 476 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 477 | "dev": true 478 | }, 479 | "node_modules/picocolors": { 480 | "version": "1.0.0", 481 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 482 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 483 | }, 484 | "node_modules/postcss": { 485 | "version": "8.4.5", 486 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", 487 | "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", 488 | "dependencies": { 489 | "nanoid": "^3.1.30", 490 | "picocolors": "^1.0.0", 491 | "source-map-js": "^1.0.1" 492 | }, 493 | "engines": { 494 | "node": "^10 || ^12 || >=14" 495 | }, 496 | "funding": { 497 | "type": "opencollective", 498 | "url": "https://opencollective.com/postcss/" 499 | } 500 | }, 501 | "node_modules/resolve": { 502 | "version": "1.20.0", 503 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 504 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 505 | "dev": true, 506 | "dependencies": { 507 | "is-core-module": "^2.2.0", 508 | "path-parse": "^1.0.6" 509 | }, 510 | "funding": { 511 | "url": "https://github.com/sponsors/ljharb" 512 | } 513 | }, 514 | "node_modules/rollup": { 515 | "version": "2.61.1", 516 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.61.1.tgz", 517 | "integrity": "sha512-BbTXlEvB8d+XFbK/7E5doIcRtxWPRiqr0eb5vQ0+2paMM04Ye4PZY5nHOQef2ix24l/L0SpLd5hwcH15QHPdvA==", 518 | "dev": true, 519 | "bin": { 520 | "rollup": "dist/bin/rollup" 521 | }, 522 | "engines": { 523 | "node": ">=10.0.0" 524 | }, 525 | "optionalDependencies": { 526 | "fsevents": "~2.3.2" 527 | } 528 | }, 529 | "node_modules/source-map": { 530 | "version": "0.6.1", 531 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 532 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 533 | "engines": { 534 | "node": ">=0.10.0" 535 | } 536 | }, 537 | "node_modules/source-map-js": { 538 | "version": "1.0.1", 539 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", 540 | "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", 541 | "engines": { 542 | "node": ">=0.10.0" 543 | } 544 | }, 545 | "node_modules/sourcemap-codec": { 546 | "version": "1.4.8", 547 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 548 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" 549 | }, 550 | "node_modules/vite": { 551 | "version": "2.7.4", 552 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.7.4.tgz", 553 | "integrity": "sha512-f+0426k9R/roz5mRNwJlQ+6UOnhCwIypJSbfgCmsVzVJe9jTTM5iRX2GWYUean+iqPBWaU/dYLryx9AoH2pmrw==", 554 | "dev": true, 555 | "dependencies": { 556 | "esbuild": "^0.13.12", 557 | "postcss": "^8.4.5", 558 | "resolve": "^1.20.0", 559 | "rollup": "^2.59.0" 560 | }, 561 | "bin": { 562 | "vite": "bin/vite.js" 563 | }, 564 | "engines": { 565 | "node": ">=12.2.0" 566 | }, 567 | "optionalDependencies": { 568 | "fsevents": "~2.3.2" 569 | }, 570 | "peerDependencies": { 571 | "less": "*", 572 | "sass": "*", 573 | "stylus": "*" 574 | }, 575 | "peerDependenciesMeta": { 576 | "less": { 577 | "optional": true 578 | }, 579 | "sass": { 580 | "optional": true 581 | }, 582 | "stylus": { 583 | "optional": true 584 | } 585 | } 586 | }, 587 | "node_modules/vue": { 588 | "version": "3.2.26", 589 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.26.tgz", 590 | "integrity": "sha512-KD4lULmskL5cCsEkfhERVRIOEDrfEL9CwAsLYpzptOGjaGFNWo3BQ9g8MAb7RaIO71rmVOziZ/uEN/rHwcUIhg==", 591 | "dependencies": { 592 | "@vue/compiler-dom": "3.2.26", 593 | "@vue/compiler-sfc": "3.2.26", 594 | "@vue/runtime-dom": "3.2.26", 595 | "@vue/server-renderer": "3.2.26", 596 | "@vue/shared": "3.2.26" 597 | } 598 | }, 599 | "node_modules/vuex": { 600 | "version": "4.0.2", 601 | "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", 602 | "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==", 603 | "dependencies": { 604 | "@vue/devtools-api": "^6.0.0-beta.11" 605 | }, 606 | "peerDependencies": { 607 | "vue": "^3.0.2" 608 | } 609 | } 610 | }, 611 | "dependencies": { 612 | "@babel/parser": { 613 | "version": "7.16.6", 614 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", 615 | "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==" 616 | }, 617 | "@vitejs/plugin-vue": { 618 | "version": "2.0.1", 619 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-2.0.1.tgz", 620 | "integrity": "sha512-wtdMnGVvys9K8tg+DxowU1ytTrdVveXr3LzdhaKakysgGXyrsfaeds2cDywtvujEASjWOwWL/OgWM+qoeM8Plg==", 621 | "dev": true, 622 | "requires": {} 623 | }, 624 | "@vue/compiler-core": { 625 | "version": "3.2.26", 626 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.26.tgz", 627 | "integrity": "sha512-N5XNBobZbaASdzY9Lga2D9Lul5vdCIOXvUMd6ThcN8zgqQhPKfCV+wfAJNNJKQkSHudnYRO2gEB+lp0iN3g2Tw==", 628 | "requires": { 629 | "@babel/parser": "^7.16.4", 630 | "@vue/shared": "3.2.26", 631 | "estree-walker": "^2.0.2", 632 | "source-map": "^0.6.1" 633 | } 634 | }, 635 | "@vue/compiler-dom": { 636 | "version": "3.2.26", 637 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.26.tgz", 638 | "integrity": "sha512-smBfaOW6mQDxcT3p9TKT6mE22vjxjJL50GFVJiI0chXYGU/xzC05QRGrW3HHVuJrmLTLx5zBhsZ2dIATERbarg==", 639 | "requires": { 640 | "@vue/compiler-core": "3.2.26", 641 | "@vue/shared": "3.2.26" 642 | } 643 | }, 644 | "@vue/compiler-sfc": { 645 | "version": "3.2.26", 646 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.26.tgz", 647 | "integrity": "sha512-ePpnfktV90UcLdsDQUh2JdiTuhV0Skv2iYXxfNMOK/F3Q+2BO0AulcVcfoksOpTJGmhhfosWfMyEaEf0UaWpIw==", 648 | "requires": { 649 | "@babel/parser": "^7.16.4", 650 | "@vue/compiler-core": "3.2.26", 651 | "@vue/compiler-dom": "3.2.26", 652 | "@vue/compiler-ssr": "3.2.26", 653 | "@vue/reactivity-transform": "3.2.26", 654 | "@vue/shared": "3.2.26", 655 | "estree-walker": "^2.0.2", 656 | "magic-string": "^0.25.7", 657 | "postcss": "^8.1.10", 658 | "source-map": "^0.6.1" 659 | } 660 | }, 661 | "@vue/compiler-ssr": { 662 | "version": "3.2.26", 663 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.26.tgz", 664 | "integrity": "sha512-2mywLX0ODc4Zn8qBoA2PDCsLEZfpUGZcyoFRLSOjyGGK6wDy2/5kyDOWtf0S0UvtoyVq95OTSGIALjZ4k2q/ag==", 665 | "requires": { 666 | "@vue/compiler-dom": "3.2.26", 667 | "@vue/shared": "3.2.26" 668 | } 669 | }, 670 | "@vue/devtools-api": { 671 | "version": "6.0.0-beta.21.1", 672 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.21.1.tgz", 673 | "integrity": "sha512-FqC4s3pm35qGVeXRGOjTsRzlkJjrBLriDS9YXbflHLsfA9FrcKzIyWnLXoNm+/7930E8rRakXuAc2QkC50swAw==" 674 | }, 675 | "@vue/reactivity": { 676 | "version": "3.2.26", 677 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.26.tgz", 678 | "integrity": "sha512-h38bxCZLW6oFJVDlCcAiUKFnXI8xP8d+eO0pcDxx+7dQfSPje2AO6M9S9QO6MrxQB7fGP0DH0dYQ8ksf6hrXKQ==", 679 | "requires": { 680 | "@vue/shared": "3.2.26" 681 | } 682 | }, 683 | "@vue/reactivity-transform": { 684 | "version": "3.2.26", 685 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.26.tgz", 686 | "integrity": "sha512-XKMyuCmzNA7nvFlYhdKwD78rcnmPb7q46uoR00zkX6yZrUmcCQ5OikiwUEVbvNhL5hBJuvbSO95jB5zkUon+eQ==", 687 | "requires": { 688 | "@babel/parser": "^7.16.4", 689 | "@vue/compiler-core": "3.2.26", 690 | "@vue/shared": "3.2.26", 691 | "estree-walker": "^2.0.2", 692 | "magic-string": "^0.25.7" 693 | } 694 | }, 695 | "@vue/runtime-core": { 696 | "version": "3.2.26", 697 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.26.tgz", 698 | "integrity": "sha512-BcYi7qZ9Nn+CJDJrHQ6Zsmxei2hDW0L6AB4vPvUQGBm2fZyC0GXd/4nVbyA2ubmuhctD5RbYY8L+5GUJszv9mQ==", 699 | "requires": { 700 | "@vue/reactivity": "3.2.26", 701 | "@vue/shared": "3.2.26" 702 | } 703 | }, 704 | "@vue/runtime-dom": { 705 | "version": "3.2.26", 706 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.26.tgz", 707 | "integrity": "sha512-dY56UIiZI+gjc4e8JQBwAifljyexfVCkIAu/WX8snh8vSOt/gMSEGwPRcl2UpYpBYeyExV8WCbgvwWRNt9cHhQ==", 708 | "requires": { 709 | "@vue/runtime-core": "3.2.26", 710 | "@vue/shared": "3.2.26", 711 | "csstype": "^2.6.8" 712 | } 713 | }, 714 | "@vue/server-renderer": { 715 | "version": "3.2.26", 716 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.26.tgz", 717 | "integrity": "sha512-Jp5SggDUvvUYSBIvYEhy76t4nr1vapY/FIFloWmQzn7UxqaHrrBpbxrqPcTrSgGrcaglj0VBp22BKJNre4aA1w==", 718 | "requires": { 719 | "@vue/compiler-ssr": "3.2.26", 720 | "@vue/shared": "3.2.26" 721 | } 722 | }, 723 | "@vue/shared": { 724 | "version": "3.2.26", 725 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.26.tgz", 726 | "integrity": "sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==" 727 | }, 728 | "csstype": { 729 | "version": "2.6.19", 730 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", 731 | "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==" 732 | }, 733 | "esbuild": { 734 | "version": "0.13.15", 735 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz", 736 | "integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==", 737 | "dev": true, 738 | "requires": { 739 | "esbuild-android-arm64": "0.13.15", 740 | "esbuild-darwin-64": "0.13.15", 741 | "esbuild-darwin-arm64": "0.13.15", 742 | "esbuild-freebsd-64": "0.13.15", 743 | "esbuild-freebsd-arm64": "0.13.15", 744 | "esbuild-linux-32": "0.13.15", 745 | "esbuild-linux-64": "0.13.15", 746 | "esbuild-linux-arm": "0.13.15", 747 | "esbuild-linux-arm64": "0.13.15", 748 | "esbuild-linux-mips64le": "0.13.15", 749 | "esbuild-linux-ppc64le": "0.13.15", 750 | "esbuild-netbsd-64": "0.13.15", 751 | "esbuild-openbsd-64": "0.13.15", 752 | "esbuild-sunos-64": "0.13.15", 753 | "esbuild-windows-32": "0.13.15", 754 | "esbuild-windows-64": "0.13.15", 755 | "esbuild-windows-arm64": "0.13.15" 756 | } 757 | }, 758 | "esbuild-android-arm64": { 759 | "version": "0.13.15", 760 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz", 761 | "integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==", 762 | "dev": true, 763 | "optional": true 764 | }, 765 | "esbuild-darwin-64": { 766 | "version": "0.13.15", 767 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz", 768 | "integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==", 769 | "dev": true, 770 | "optional": true 771 | }, 772 | "esbuild-darwin-arm64": { 773 | "version": "0.13.15", 774 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz", 775 | "integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==", 776 | "dev": true, 777 | "optional": true 778 | }, 779 | "esbuild-freebsd-64": { 780 | "version": "0.13.15", 781 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz", 782 | "integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==", 783 | "dev": true, 784 | "optional": true 785 | }, 786 | "esbuild-freebsd-arm64": { 787 | "version": "0.13.15", 788 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz", 789 | "integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==", 790 | "dev": true, 791 | "optional": true 792 | }, 793 | "esbuild-linux-32": { 794 | "version": "0.13.15", 795 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz", 796 | "integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==", 797 | "dev": true, 798 | "optional": true 799 | }, 800 | "esbuild-linux-64": { 801 | "version": "0.13.15", 802 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz", 803 | "integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==", 804 | "dev": true, 805 | "optional": true 806 | }, 807 | "esbuild-linux-arm": { 808 | "version": "0.13.15", 809 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz", 810 | "integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==", 811 | "dev": true, 812 | "optional": true 813 | }, 814 | "esbuild-linux-arm64": { 815 | "version": "0.13.15", 816 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz", 817 | "integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==", 818 | "dev": true, 819 | "optional": true 820 | }, 821 | "esbuild-linux-mips64le": { 822 | "version": "0.13.15", 823 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz", 824 | "integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==", 825 | "dev": true, 826 | "optional": true 827 | }, 828 | "esbuild-linux-ppc64le": { 829 | "version": "0.13.15", 830 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz", 831 | "integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==", 832 | "dev": true, 833 | "optional": true 834 | }, 835 | "esbuild-netbsd-64": { 836 | "version": "0.13.15", 837 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz", 838 | "integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==", 839 | "dev": true, 840 | "optional": true 841 | }, 842 | "esbuild-openbsd-64": { 843 | "version": "0.13.15", 844 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz", 845 | "integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==", 846 | "dev": true, 847 | "optional": true 848 | }, 849 | "esbuild-sunos-64": { 850 | "version": "0.13.15", 851 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz", 852 | "integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==", 853 | "dev": true, 854 | "optional": true 855 | }, 856 | "esbuild-windows-32": { 857 | "version": "0.13.15", 858 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz", 859 | "integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==", 860 | "dev": true, 861 | "optional": true 862 | }, 863 | "esbuild-windows-64": { 864 | "version": "0.13.15", 865 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz", 866 | "integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==", 867 | "dev": true, 868 | "optional": true 869 | }, 870 | "esbuild-windows-arm64": { 871 | "version": "0.13.15", 872 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz", 873 | "integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==", 874 | "dev": true, 875 | "optional": true 876 | }, 877 | "estree-walker": { 878 | "version": "2.0.2", 879 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 880 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 881 | }, 882 | "fsevents": { 883 | "version": "2.3.2", 884 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 885 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 886 | "dev": true, 887 | "optional": true 888 | }, 889 | "function-bind": { 890 | "version": "1.1.1", 891 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 892 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 893 | "dev": true 894 | }, 895 | "has": { 896 | "version": "1.0.3", 897 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 898 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 899 | "dev": true, 900 | "requires": { 901 | "function-bind": "^1.1.1" 902 | } 903 | }, 904 | "is-core-module": { 905 | "version": "2.8.0", 906 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", 907 | "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", 908 | "dev": true, 909 | "requires": { 910 | "has": "^1.0.3" 911 | } 912 | }, 913 | "magic-string": { 914 | "version": "0.25.7", 915 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", 916 | "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", 917 | "requires": { 918 | "sourcemap-codec": "^1.4.4" 919 | } 920 | }, 921 | "nanoid": { 922 | "version": "3.1.30", 923 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", 924 | "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" 925 | }, 926 | "path-parse": { 927 | "version": "1.0.7", 928 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 929 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 930 | "dev": true 931 | }, 932 | "picocolors": { 933 | "version": "1.0.0", 934 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 935 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 936 | }, 937 | "postcss": { 938 | "version": "8.4.5", 939 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", 940 | "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", 941 | "requires": { 942 | "nanoid": "^3.1.30", 943 | "picocolors": "^1.0.0", 944 | "source-map-js": "^1.0.1" 945 | } 946 | }, 947 | "resolve": { 948 | "version": "1.20.0", 949 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 950 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 951 | "dev": true, 952 | "requires": { 953 | "is-core-module": "^2.2.0", 954 | "path-parse": "^1.0.6" 955 | } 956 | }, 957 | "rollup": { 958 | "version": "2.61.1", 959 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.61.1.tgz", 960 | "integrity": "sha512-BbTXlEvB8d+XFbK/7E5doIcRtxWPRiqr0eb5vQ0+2paMM04Ye4PZY5nHOQef2ix24l/L0SpLd5hwcH15QHPdvA==", 961 | "dev": true, 962 | "requires": { 963 | "fsevents": "~2.3.2" 964 | } 965 | }, 966 | "source-map": { 967 | "version": "0.6.1", 968 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 969 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 970 | }, 971 | "source-map-js": { 972 | "version": "1.0.1", 973 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", 974 | "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==" 975 | }, 976 | "sourcemap-codec": { 977 | "version": "1.4.8", 978 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 979 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" 980 | }, 981 | "vite": { 982 | "version": "2.7.4", 983 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.7.4.tgz", 984 | "integrity": "sha512-f+0426k9R/roz5mRNwJlQ+6UOnhCwIypJSbfgCmsVzVJe9jTTM5iRX2GWYUean+iqPBWaU/dYLryx9AoH2pmrw==", 985 | "dev": true, 986 | "requires": { 987 | "esbuild": "^0.13.12", 988 | "fsevents": "~2.3.2", 989 | "postcss": "^8.4.5", 990 | "resolve": "^1.20.0", 991 | "rollup": "^2.59.0" 992 | } 993 | }, 994 | "vue": { 995 | "version": "3.2.26", 996 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.26.tgz", 997 | "integrity": "sha512-KD4lULmskL5cCsEkfhERVRIOEDrfEL9CwAsLYpzptOGjaGFNWo3BQ9g8MAb7RaIO71rmVOziZ/uEN/rHwcUIhg==", 998 | "requires": { 999 | "@vue/compiler-dom": "3.2.26", 1000 | "@vue/compiler-sfc": "3.2.26", 1001 | "@vue/runtime-dom": "3.2.26", 1002 | "@vue/server-renderer": "3.2.26", 1003 | "@vue/shared": "3.2.26" 1004 | } 1005 | }, 1006 | "vuex": { 1007 | "version": "4.0.2", 1008 | "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", 1009 | "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==", 1010 | "requires": { 1011 | "@vue/devtools-api": "^6.0.0-beta.11" 1012 | } 1013 | } 1014 | } 1015 | } 1016 | -------------------------------------------------------------------------------- /composition-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "composition-api", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vite build", 7 | "preview": "vite preview" 8 | }, 9 | "dependencies": { 10 | "vue": "^3.2.25", 11 | "vuex": "^4.0.2" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^2.0.0", 15 | "vite": "^2.7.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /composition-api/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/composition-api/public/favicon.ico -------------------------------------------------------------------------------- /composition-api/src/App.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 57 | -------------------------------------------------------------------------------- /composition-api/src/Money.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | -------------------------------------------------------------------------------- /composition-api/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/composition-api/src/assets/logo.png -------------------------------------------------------------------------------- /composition-api/src/composables/useRate.js: -------------------------------------------------------------------------------- 1 | import { ref, readonly } from "vue" 2 | 3 | const rate = ref(1.14) 4 | 5 | export function useRate() { 6 | const setRate = (newRate) => rate.value = newRate 7 | 8 | return { 9 | rate: readonly(rate), 10 | setRate 11 | } 12 | } -------------------------------------------------------------------------------- /composition-api/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import { createStore } from "vuex" 4 | import store from "./store/index" 5 | 6 | const app = createApp(App) 7 | app.use(createStore(store)) 8 | app.mount('#app') 9 | -------------------------------------------------------------------------------- /composition-api/src/store/index.js: -------------------------------------------------------------------------------- 1 | const state = () => ({ 2 | rate: 1.14 3 | }) 4 | const mutations = { 5 | setRate(state, payload) { 6 | state.rate = payload 7 | } 8 | } 9 | export default { 10 | state, 11 | mutations 12 | } -------------------------------------------------------------------------------- /composition-api/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /first-unit-test/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /first-unit-test/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /first-unit-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "test": "vitest", 10 | "test-once": "vitest run", 11 | "test-verbose": "vitest run --reporter verbose", 12 | "coverage": "vitest run --coverage" 13 | }, 14 | "dependencies": { 15 | "node-fetch": "^3.2.5", 16 | "vue": "^3.2.25" 17 | }, 18 | "devDependencies": { 19 | "@vitejs/plugin-vue": "^2.3.3", 20 | "@vue/test-utils": "^2.0.0-rc.18", 21 | "c8": "^7.11.3", 22 | "jsdom": "^19.0.0", 23 | "msw": "^0.42.1", 24 | "vite": "^2.9.9", 25 | "vitest": "^0.12.6" 26 | } 27 | } -------------------------------------------------------------------------------- /first-unit-test/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/first-unit-test/public/favicon.ico -------------------------------------------------------------------------------- /first-unit-test/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /first-unit-test/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/first-unit-test/src/assets/logo.png -------------------------------------------------------------------------------- /first-unit-test/src/components/Form.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import Form from './Form.vue' 4 | 5 | test('The component can be used', () => { 6 | expect(Form).toBeTruthy() 7 | }) 8 | 9 | document.body.innerHTML = `
` 10 | 11 | test('The firm is being rendered and can be submitted', async () => { 12 | const wrapper = mount(Form, { 13 | attachTo: document.getElementById('app') 14 | }) 15 | const username = wrapper.get('input[name="username"]') 16 | const password = wrapper.get('input[name="password"]') 17 | const button = wrapper.get('button[type="submit"]') 18 | 19 | expect(username.element.value).toBe('') 20 | expect(password.element.value).toBe('') 21 | 22 | username.setValue('test') 23 | password.setValue('test') 24 | 25 | expect(wrapper.find('#submitted').exists()).toBe(false) 26 | await button.trigger('click') 27 | expect(wrapper.emitted()).toHaveProperty('submit') 28 | expect(wrapper.find('#submitted').exists()).toBe(true) 29 | }) -------------------------------------------------------------------------------- /first-unit-test/src/components/Form.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | -------------------------------------------------------------------------------- /first-unit-test/src/components/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect } from 'vitest' 2 | import { mount } from '@vue/test-utils' 3 | import HelloWorld from './HelloWorld.vue' 4 | 5 | test('The component can be used', () => { 6 | expect(HelloWorld).toBeTruthy() 7 | }) 8 | 9 | test('The component renders welcome message', () => { 10 | const wrapper = mount(HelloWorld, { 11 | props: { 12 | msg: 'This message comes from a test' 13 | } 14 | }) 15 | expect(wrapper.text()).toContain( 16 | 'This message comes from a test' 17 | ) 18 | }) 19 | 20 | test('Counter should be increased when the button is pressed', async () => { 21 | const wrapper = mount(HelloWorld, { 22 | props: { 23 | msg: null 24 | } 25 | }) 26 | const button = wrapper.get('button') 27 | expect(button.text()).toContain( 28 | 'count is: 0' 29 | ) 30 | await button.trigger('click') 31 | expect(button.text()).toContain( 32 | 'count is: 1' 33 | ) 34 | }) -------------------------------------------------------------------------------- /first-unit-test/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 41 | 42 | 47 | -------------------------------------------------------------------------------- /first-unit-test/src/composables/useUser.js: -------------------------------------------------------------------------------- 1 | import { ref, onMounted } from 'vue' 2 | 3 | const fetchGitHubProfileIntoRef = async (user) => { 4 | const response = await fetch( 5 | 'https://api.github.com/users/piotr-jura-udemy' 6 | ) 7 | user.value = await response.json(); 8 | } 9 | 10 | export const useUser = () => { 11 | const user = ref(null) 12 | onMounted(() => fetchGitHubProfileIntoRef(user)) 13 | return { user } 14 | } 15 | 16 | export const useUserSimple = (username) => { 17 | const user = ref(null) 18 | const loadUser = async () => fetchGitHubProfileIntoRef(user) 19 | 20 | return { 21 | user, loadUser 22 | } 23 | } -------------------------------------------------------------------------------- /first-unit-test/src/composables/useUser.spec.js: -------------------------------------------------------------------------------- 1 | import { test, expect, vi, beforeAll, afterAll, describe, it } from 'vitest' 2 | import { useUserSimple, useUser } from './useUser' 3 | import nodeFetch from 'node-fetch' 4 | import { setupServer } from 'msw/node' 5 | import handlers from './../mocks/handlers' 6 | import { defineComponent } from 'vue' 7 | import { mount, flushPromises } from '@vue/test-utils' 8 | 9 | const server = setupServer(...handlers) 10 | 11 | beforeAll(() => server.listen()) 12 | afterAll(() => server.close()) 13 | 14 | window.fetch = nodeFetch 15 | 16 | describe('Test Composables', () => { 17 | test('Test simple composable by calling it directly', async () => { 18 | const { user, loadUser } = useUserSimple('piotr-jura-udemy') 19 | expect(user.value).toBe(null) 20 | await loadUser() 21 | expect(user.value).toHaveProperty('name', 'Piotr Jura') 22 | expect(user.value).toHaveProperty('id', 39863283) 23 | }) 24 | 25 | test('The user data is being fetched when the component gets mounted', async () => { 26 | const TestComponent = defineComponent({ 27 | template: `
{{user.name}}
`, 28 | setup() { 29 | return { 30 | ...useUser() 31 | } 32 | } 33 | }) 34 | const wrapper = mount(TestComponent) 35 | // await flushPromises() 36 | await new Promise(resolve => setTimeout(resolve, 300)) 37 | expect(wrapper.html()).toEqual('
Piotr Jura
') 38 | }) 39 | }) 40 | 41 | 42 | const realTaxRule = (amount) => { 43 | if (amount < 100) { 44 | return 0.05 45 | } else if (amount >= 100 && amount < 200) { 46 | return 0.10 47 | } else { 48 | return 0.20 49 | } 50 | } 51 | const calculator = { 52 | tax: (amount, taxRuleFunc) => { 53 | console.log('Original tax() called: ') 54 | 55 | if (amount === 0) { 56 | return 0 57 | } 58 | 59 | return taxRuleFunc(amount) * amount 60 | }, 61 | } 62 | 63 | describe('Mock testing', () => { 64 | it('Test the calculator without mocking', () => { 65 | const tax = calculator.tax(100, realTaxRule) 66 | expect(tax).toBe(10) 67 | }) 68 | 69 | it('Test the calcultor using mocks', () => { 70 | const mock = vi.fn().mockReturnValue(0.19) 71 | expect(calculator.tax(100, mock)).toBe(19) 72 | }) 73 | }) 74 | 75 | test('Using spies', () => { 76 | const spy = vi.spyOn(calculator, 'tax') 77 | calculator.tax(100, realTaxRule) 78 | 79 | expect(spy).toHaveBeenCalled() 80 | expect(spy).toHaveReturnedWith(10) 81 | expect(spy).toHaveBeenCalledWith(100, realTaxRule) 82 | 83 | const spy2 = vi.fn(realTaxRule) 84 | calculator.tax(100, spy2) 85 | expect(spy2).toHaveBeenCalled() 86 | expect(spy2).toHaveBeenCalledWith(100) 87 | 88 | const spy3 = vi.fn(realTaxRule) 89 | calculator.tax(0, spy2) 90 | expect(spy3).not.toHaveBeenCalled 91 | }) -------------------------------------------------------------------------------- /first-unit-test/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') -------------------------------------------------------------------------------- /first-unit-test/src/mocks/handlers.js: -------------------------------------------------------------------------------- 1 | import { rest } from 'msw' 2 | 3 | export default [ 4 | rest.get( 5 | 'https://api.github.com/users/piotr-jura-udemy', 6 | (req, res, ctx) => { 7 | return res( 8 | ctx.json({ 9 | name: 'Piotr Jura', 10 | id: 39863283 11 | }) 12 | ) 13 | }) 14 | ] -------------------------------------------------------------------------------- /first-unit-test/test/basic.test.js: -------------------------------------------------------------------------------- 1 | import { test, expect, beforeEach } from 'vitest' 2 | 3 | test('2+2=4', () => { 4 | expect(2 + 2).toBe(4) 5 | }) 6 | 7 | const iAmHere = null 8 | 9 | test('Testing the API', () => { 10 | // expect(0.2 + 0.1).toBe(0.3) 11 | expect(0.2 + 0.1).toBeCloseTo(0.3) 12 | expect(iAmHere).toBeDefined() 13 | expect('Hello').toBeTruthy() 14 | }) 15 | 16 | class Example { } 17 | const example = new Example 18 | 19 | test('The object is right', () => { 20 | expect(example).toBeDefined() 21 | expect(example).toBeInstanceOf(Example) 22 | }) 23 | 24 | test('Checking some objects', () => { 25 | const object1 = { 26 | name: 'Piotr', 27 | type: 'Instructor', 28 | grade: 1 29 | } 30 | const object2 = { 31 | name: 'Piotr', 32 | grade: 1, 33 | type: 'Instructor', 34 | } 35 | 36 | const subset = { 37 | type: 'Instructor' 38 | } 39 | 40 | expect(object1).toEqual(object2) 41 | expect(object1).toMatchObject(subset) 42 | }) 43 | 44 | test('Testing arrays', () => { 45 | expect([1, 2]).toEqual([1, 2]) 46 | expect([1, 2, 3]).toContain(2) 47 | }) 48 | 49 | let fakeData = [2, 1, 3] 50 | 51 | beforeEach(() => { 52 | fakeData = [2, 1, 3] 53 | }) 54 | 55 | test('Item is removed from array', () => { 56 | const value = fakeData.shift() 57 | expect(value).toBe(2) 58 | expect(fakeData).toHaveLength(2) 59 | }) 60 | 61 | test('Test the basic array', () => { 62 | expect(fakeData).toHaveLength(3) 63 | }) -------------------------------------------------------------------------------- /first-unit-test/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()], 7 | test: { 8 | environment: 'jsdom' 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | Vue 3 Components 10 | 11 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | Only pending tasks 23 | 24 |
25 |
26 | 29 | 30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /options-api-to-composition-api/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /options-api-to-composition-api/.env.development: -------------------------------------------------------------------------------- 1 | API_URL=http://localhost:8080/api -------------------------------------------------------------------------------- /options-api-to-composition-api/.env.production: -------------------------------------------------------------------------------- 1 | API_URL=http://api.yourdomain.com/api -------------------------------------------------------------------------------- /options-api-to-composition-api/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"], 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | }, 10 | rules: { 11 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 12 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /options-api-to-composition-api/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /options-api-to-composition-api/README.md: -------------------------------------------------------------------------------- 1 | # sfc 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /options-api-to-composition-api/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /options-api-to-composition-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sfc", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^3.0.0", 13 | "vuex": "^4.0.2" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "~4.5.0", 17 | "@vue/cli-plugin-eslint": "~4.5.0", 18 | "@vue/cli-service": "~4.5.0", 19 | "@vue/compiler-sfc": "^3.0.0", 20 | "@vue/eslint-config-prettier": "^6.0.0", 21 | "babel-eslint": "^10.1.0", 22 | "eslint": "^6.7.2", 23 | "eslint-plugin-prettier": "^3.3.1", 24 | "eslint-plugin-vue": "^7.0.0", 25 | "prettier": "^2.2.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /options-api-to-composition-api/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/options-api-to-composition-api/public/favicon.ico -------------------------------------------------------------------------------- /options-api-to-composition-api/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 12 | 13 | <%= htmlWebpackPlugin.options.title %> 14 | 15 | 16 | 17 | 18 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/App.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 78 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/Landing.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/base/BaseCheckbox.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/base/BaseSmallListButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/base/BaseTextButton.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/project/ProjectList.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/project/ProjectListItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 26 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/project/ProjectSummaryLine.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 34 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/task/AddTaskInput.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/task/TodoListItem.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 40 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/task/TodoListItemMenu.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/components/task/TodoListItemMenuMove.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 38 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/landing.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import Landing from "./Landing.vue"; 3 | 4 | createApp(Landing).mount("#app"); 5 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | import store from "./store"; 4 | 5 | const app = createApp(App); 6 | app.config.unwrapInjectedRef = true; 7 | app.use(store); 8 | app.mount("#app"); 9 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/store/actions-types.js: -------------------------------------------------------------------------------- 1 | export const MOVE_TASK = "MOVE_TASK"; 2 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | // import { localStoragePlugin } from "./plugins/localStorage"; 3 | import application from "./modules/application"; 4 | import project from "./modules/project"; 5 | 6 | const store = createStore({ 7 | modules: { 8 | project, 9 | application, 10 | }, 11 | state() { 12 | return {}; 13 | }, 14 | getters: {}, 15 | mutations: {}, 16 | actions: {}, 17 | // plugins: [localStoragePlugin], 18 | }); 19 | 20 | export default store; 21 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/store/modules/application.js: -------------------------------------------------------------------------------- 1 | import { SET_ONLY_PENDING } from "./../mutation-types"; 2 | 3 | const state = () => ({ 4 | onlyPending: false, 5 | }); 6 | 7 | const mutations = { 8 | [SET_ONLY_PENDING](state, payload) { 9 | state.onlyPending = payload; 10 | }, 11 | }; 12 | 13 | export default { 14 | namespaced: true, 15 | state, 16 | mutations, 17 | }; 18 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/store/modules/project.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_TASK, 3 | REMOVE_TASK, 4 | UPDATE_TASK, 5 | SET_ACTIVE_PROJECT, 6 | } from "./../mutation-types"; 7 | import { MOVE_TASK } from "./../actions-types"; 8 | 9 | function getProjectById(state, id) { 10 | return state.projects.find((project) => project.id === id); 11 | } 12 | 13 | function getProjectAndTaskIndex(state, { projectId, taskId }) { 14 | const project = getProjectById(state, projectId); 15 | 16 | return { 17 | project, 18 | taskIndex: project?.tasks?.findIndex((task) => task.id === taskId), 19 | }; 20 | } 21 | 22 | const state = () => ({ 23 | activeProjectId: 1, 24 | projects: [ 25 | { 26 | id: 1, 27 | name: "First Project", 28 | tasks: [ 29 | { 30 | id: 1, 31 | description: "Buy food for the dog", 32 | priority: false, 33 | done: false, 34 | }, 35 | { 36 | id: 2, 37 | description: "Pay the bills", 38 | priority: true, 39 | done: false, 40 | }, 41 | { 42 | id: 3, 43 | description: "Buy some computer games", 44 | priority: false, 45 | done: false, 46 | }, 47 | { 48 | id: 4, 49 | description: "Go to the gym", 50 | priority: false, 51 | done: false, 52 | }, 53 | ], 54 | }, 55 | { 56 | id: 2, 57 | name: "Life Project", 58 | tasks: [ 59 | { 60 | id: 101, 61 | description: "Visit parents", 62 | priority: false, 63 | done: false, 64 | }, 65 | { 66 | id: 102, 67 | description: "Visit uncles", 68 | priority: true, 69 | done: false, 70 | }, 71 | { 72 | id: 103, 73 | description: "Go around the world", 74 | priority: false, 75 | done: false, 76 | }, 77 | { 78 | id: 104, 79 | description: "Quit smoking", 80 | priority: false, 81 | done: false, 82 | }, 83 | ], 84 | }, 85 | ], 86 | }); 87 | const getters = { 88 | activeProject(state) { 89 | return getProjectById(state, state.activeProjectId); 90 | }, 91 | projectsWithStats(state) { 92 | return state.projects.map((project) => ({ 93 | id: project.id, 94 | ...project, 95 | notDoneCount: project.tasks.filter((task) => !task.done).length, 96 | })); 97 | }, 98 | activeProjectTasks(_, getters) { 99 | return getters.activeProject?.tasks ?? []; 100 | }, 101 | }; 102 | const mutations = { 103 | /* 104 | payload: { 105 | projectId: number, 106 | task: { 107 | id: number, 108 | description: string, 109 | done: boolean, 110 | priority: boolean, 111 | } 112 | } 113 | */ 114 | [ADD_TASK](state, payload) { 115 | getProjectById(state, payload.projectId)?.tasks.push(payload.task); 116 | }, 117 | [REMOVE_TASK](state, payload) { 118 | const { project, taskIndex } = getProjectAndTaskIndex(state, payload); 119 | 120 | if (taskIndex !== undefined && taskIndex !== -1) { 121 | project.tasks.splice(taskIndex, 1); 122 | } 123 | }, 124 | [UPDATE_TASK](state, payload) { 125 | const { project, taskIndex } = getProjectAndTaskIndex(state, payload); 126 | 127 | if (taskIndex !== undefined && taskIndex !== -1) { 128 | project.tasks[taskIndex] = payload.task; 129 | } 130 | }, 131 | [SET_ACTIVE_PROJECT](state, activeProjectId) { 132 | state.activeProjectId = activeProjectId; 133 | }, 134 | }; 135 | const actions = { 136 | [MOVE_TASK]({ commit, state }, { taskId, fromProjectId, toProjectId }) { 137 | const { project, taskIndex } = getProjectAndTaskIndex(state, { 138 | taskId, 139 | projectId: fromProjectId, 140 | }); 141 | commit(ADD_TASK, { 142 | task: project.tasks[taskIndex], 143 | projectId: toProjectId, 144 | }); 145 | commit(REMOVE_TASK, { 146 | taskId, 147 | projectId: fromProjectId, 148 | }); 149 | }, 150 | }; 151 | 152 | export default { 153 | namespaced: true, 154 | state, 155 | getters, 156 | mutations, 157 | actions, 158 | }; 159 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ADD_TASK = "ADD_TASK"; 2 | export const REMOVE_TASK = "REMOVE_TASK"; 3 | export const UPDATE_TASK = "UPDATE_TASK"; 4 | export const SET_ONLY_PENDING = "SET_ONLY_PENDING"; 5 | export const SET_ACTIVE_PROJECT = "SET_ACTIVE_PROJECT"; 6 | -------------------------------------------------------------------------------- /options-api-to-composition-api/src/store/plugins/localStorage.js: -------------------------------------------------------------------------------- 1 | const KEY = "vuex-storage"; 2 | 3 | export const localStoragePlugin = (store) => { 4 | console.log("Plugin was initialized"); 5 | store.replaceState( 6 | Object.assign(store.state, JSON.parse(window.localStorage.getItem(KEY))) 7 | ); 8 | 9 | store.subscribe((mutation, state) => { 10 | console.log(mutation); 11 | window.localStorage.setItem(KEY, JSON.stringify(state)); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /options-api-to-composition-api/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: process.env.NODE_ENV === "production" ? "/app" : "", 3 | pages: { 4 | index: { 5 | title: "Todo Applicaiton", 6 | entry: "/src/main.js", 7 | }, 8 | landing: { 9 | title: "Landing Page", 10 | entry: "/src/landing.js", 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /router/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /router/README.md: -------------------------------------------------------------------------------- 1 | # router 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /router/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "router", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^3.0.0", 13 | "vue-router": "^4.0.11" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "~4.5.0", 17 | "@vue/cli-plugin-eslint": "~4.5.0", 18 | "@vue/cli-service": "~4.5.0", 19 | "@vue/compiler-sfc": "^3.0.0", 20 | "babel-eslint": "^10.1.0", 21 | "eslint": "^6.7.2", 22 | "eslint-plugin-vue": "^7.0.0" 23 | }, 24 | "eslintConfig": { 25 | "root": true, 26 | "env": { 27 | "node": true 28 | }, 29 | "extends": [ 30 | "plugin:vue/vue3-essential", 31 | "eslint:recommended" 32 | ], 33 | "parserOptions": { 34 | "parser": "babel-eslint" 35 | }, 36 | "rules": {} 37 | }, 38 | "browserslist": [ 39 | "> 1%", 40 | "last 2 versions", 41 | "not dead" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /router/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/router/public/favicon.ico -------------------------------------------------------------------------------- /router/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /router/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /router/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/router/src/assets/logo.png -------------------------------------------------------------------------------- /router/src/components/ArticleList.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /router/src/data.js: -------------------------------------------------------------------------------- 1 | export const articles = { 2 | 1: { 3 | id: 1, 4 | title: "An interesting article about cars and videos", 5 | tags: ["cars", "videos"], 6 | comments: [ 7 | { 8 | id: 1, 9 | comment: "I like the post 1!" 10 | }, 11 | { 12 | id: 2, 13 | comment: "Me too!" 14 | } 15 | ] 16 | }, 17 | 2: { 18 | id: 2, 19 | title: "This about video making", 20 | tags: ["cars"], 21 | comments: [{ 22 | id: 1, 23 | comment: "I like the post 2!" 24 | }, 25 | { 26 | id: 2, 27 | comment: "Me too!" 28 | }] 29 | }, 30 | 3: { 31 | id: 3, 32 | title: "Book sales are increasing", 33 | tags: ["books"], 34 | comments: [{ 35 | id: 1, 36 | comment: "I like the post 3!" 37 | }, 38 | { 39 | id: 2, 40 | comment: "Me too!" 41 | }] 42 | }, 43 | }; -------------------------------------------------------------------------------- /router/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createRouter, createWebHashHistory } from 'vue-router' 3 | import App from './App.vue' 4 | import HomePage from './pages/HomePage.vue' 5 | import AboutPage from './pages/AboutPage.vue' 6 | import ArticlePage from './pages/ArticlePage.vue' 7 | import NotFoundPage from './pages/NotFoundPage.vue' 8 | import ArticlesByTagPage from './pages/ArticlesByTagPage.vue' 9 | import ArticleCommentList from './pages/ArticlePage/ArticleCommentList.vue' 10 | import ArticleAuthor from './pages/ArticlePage/ArticleAuthor.vue' 11 | import LoginPage from './pages/LoginPage.vue' 12 | 13 | const routes = [ 14 | { 15 | path: '/', 16 | component: HomePage, 17 | name: 'home', 18 | alias: ['/home', '/homepage'] 19 | }, 20 | // { 21 | // path: '/home', 22 | // redirect: { 23 | // name: 'home' 24 | // } 25 | // }, 26 | { 27 | path: '/about', 28 | component: AboutPage, 29 | name: 'about' 30 | }, 31 | { 32 | path: '/articles/:id(\\d+)', 33 | name: 'articles', 34 | component: ArticlePage, 35 | props: true, 36 | children: [ 37 | { 38 | name: 'articles.comments', 39 | path: '', 40 | component: ArticleCommentList, 41 | props: true 42 | }, 43 | { 44 | name: 'articles.author', 45 | path: 'author', 46 | component: ArticleAuthor, 47 | props: true 48 | } 49 | ] 50 | }, 51 | { 52 | path: '/tags/:tags+', 53 | name: 'tags', 54 | component: ArticlesByTagPage, 55 | props: true 56 | }, 57 | { 58 | path: '/login', 59 | name: 'login', 60 | component: LoginPage, 61 | }, 62 | { 63 | path: '/:url(.+)?', 64 | name: 'not-found', 65 | component: NotFoundPage 66 | } 67 | ]; 68 | 69 | const router = createRouter({ 70 | history: createWebHashHistory(), 71 | routes 72 | }); 73 | 74 | router.beforeEach((to, from) => { 75 | console.log(`Global beforeEach, from ${from.name} to ${to.name}`); 76 | 77 | if (['login', 'home', 'about'].includes(to.name)) { 78 | return true; 79 | } 80 | 81 | return { name: 'login', query: { redirect: to.fullPath } }; 82 | }); 83 | 84 | const app = createApp(App); 85 | app.use(router); 86 | 87 | app.mount('#app'); 88 | -------------------------------------------------------------------------------- /router/src/pages/AboutPage.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /router/src/pages/ArticlePage.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /router/src/pages/ArticlePage/ArticleAuthor.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /router/src/pages/ArticlePage/ArticleCommentList.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /router/src/pages/ArticlesByTagPage.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /router/src/pages/HomePage.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | -------------------------------------------------------------------------------- /router/src/pages/LoginPage.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /router/src/pages/NotFoundPage.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /single-file-components/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /single-file-components/.env.development: -------------------------------------------------------------------------------- 1 | API_URL=http://localhost:8080/api -------------------------------------------------------------------------------- /single-file-components/.env.production: -------------------------------------------------------------------------------- 1 | API_URL=http://api.yourdomain.com/api -------------------------------------------------------------------------------- /single-file-components/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"], 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | }, 10 | rules: { 11 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 12 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /single-file-components/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /single-file-components/README.md: -------------------------------------------------------------------------------- 1 | # sfc 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /single-file-components/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /single-file-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sfc", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^3.0.0" 13 | }, 14 | "devDependencies": { 15 | "@vue/cli-plugin-babel": "~4.5.0", 16 | "@vue/cli-plugin-eslint": "~4.5.0", 17 | "@vue/cli-service": "~4.5.0", 18 | "@vue/compiler-sfc": "^3.0.0", 19 | "@vue/eslint-config-prettier": "^6.0.0", 20 | "babel-eslint": "^10.1.0", 21 | "eslint": "^6.7.2", 22 | "eslint-plugin-prettier": "^3.3.1", 23 | "eslint-plugin-vue": "^7.0.0", 24 | "prettier": "^2.2.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /single-file-components/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/single-file-components/public/favicon.ico -------------------------------------------------------------------------------- /single-file-components/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 12 | 13 | <%= htmlWebpackPlugin.options.title %> 14 | 15 | 16 | 17 | 18 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /single-file-components/src/App.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 85 | -------------------------------------------------------------------------------- /single-file-components/src/Landing.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /single-file-components/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/single-file-components/src/assets/logo.png -------------------------------------------------------------------------------- /single-file-components/src/components/AddTaskInput.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /single-file-components/src/components/BaseCheckbox.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | -------------------------------------------------------------------------------- /single-file-components/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 88 | 89 | 97 | 98 | 99 | 115 | -------------------------------------------------------------------------------- /single-file-components/src/components/TodoListItem.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 41 | -------------------------------------------------------------------------------- /single-file-components/src/landing.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import Landing from "./Landing.vue"; 3 | 4 | createApp(Landing).mount("#app"); 5 | -------------------------------------------------------------------------------- /single-file-components/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | 4 | createApp(App).mount("#app"); 5 | -------------------------------------------------------------------------------- /single-file-components/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: process.env.NODE_ENV === 'production' 3 | ? '/app' 4 | : '', 5 | pages: { 6 | index: { 7 | title: 'Todo Applicaiton', 8 | entry: '/src/main.js' 9 | }, 10 | landing: { 11 | title: 'Landing Page', 12 | entry: '/src/landing.js' 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /the-game/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /the-game/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /the-game/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "the-game", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "pinia": "^2.0.13", 12 | "vue": "^3.2.25", 13 | "vue-router": "^4.0.15" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-vue": "^2.3.1", 17 | "vite": "^2.9.7" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /the-game/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/the-game/public/favicon.ico -------------------------------------------------------------------------------- /the-game/src/App.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /the-game/src/components/Counter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /the-game/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createPinia } from 'pinia' 3 | import App from './App.vue' 4 | import router from './router' 5 | 6 | const app = createApp(App) 7 | app.use(createPinia()) 8 | app.use(router) 9 | app.mount('#app') 10 | -------------------------------------------------------------------------------- /the-game/src/router.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router' 2 | 3 | const routes = [ 4 | { 5 | path: '/', 6 | name: 'home', 7 | component: () => import('./views/Game.vue') 8 | }, 9 | { 10 | path: '/hall-of-fame', 11 | name: 'hall-of-fame', 12 | component: () => import('./views/HallOfFame.vue') 13 | } 14 | ] 15 | 16 | const router = createRouter({ 17 | routes, 18 | history: createWebHashHistory() 19 | // domain.local/#/hall-of-fame 20 | }) 21 | 22 | export default router -------------------------------------------------------------------------------- /the-game/src/stores/counter.js: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | 3 | export const useCounterStore = defineStore( 4 | 'counter', 5 | { 6 | state: () => ({ 7 | count: 0, 8 | scores: [] 9 | }), 10 | actions: { 11 | addScore() { 12 | this.scores.unshift({ 13 | score: this.count, 14 | when: new Date() 15 | }) 16 | this.count = 0 17 | } 18 | }, 19 | getters: { 20 | sortedByBest: (state) => 21 | state.scores.sort( 22 | (a, b) => b.score - a.score 23 | ), 24 | highScore: (state) => 25 | state.scores.reduce( 26 | (highScore, item) => item.score > highScore ? item.score : highScore, 27 | 0 28 | ) 29 | } 30 | } 31 | ) -------------------------------------------------------------------------------- /the-game/src/views/Game.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /the-game/src/views/HallOfFame.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /the-game/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /todo-firebase/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /todo-firebase/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 15 | 16 | 17 | -------------------------------------------------------------------------------- /todo-firebase/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-firebase", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "firebase": "^9.6.5", 12 | "firebase-tools": "^10.1.4", 13 | "vue": "^3.2.25", 14 | "vue-router": "^4.0.14", 15 | "vuex": "^4.0.2" 16 | }, 17 | "devDependencies": { 18 | "@vitejs/plugin-vue": "^2.2.0", 19 | "autoprefixer": "^10.4.4", 20 | "postcss": "^8.4.12", 21 | "tailwindcss": "^3.0.23", 22 | "vite": "^2.8.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /todo-firebase/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /todo-firebase/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/todo-firebase/public/favicon.ico -------------------------------------------------------------------------------- /todo-firebase/src/App.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /todo-firebase/src/Landing.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /todo-firebase/src/components/base/BaseCheckbox.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /todo-firebase/src/components/base/BaseSmallListButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /todo-firebase/src/components/base/BaseTextButton.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /todo-firebase/src/components/project/ProjectAdd.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | -------------------------------------------------------------------------------- /todo-firebase/src/components/project/ProjectList.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /todo-firebase/src/components/project/ProjectListItem.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /todo-firebase/src/components/project/ProjectSummaryLine.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 34 | -------------------------------------------------------------------------------- /todo-firebase/src/components/task/AddTaskInput.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /todo-firebase/src/components/task/TodoListItem.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 38 | 39 | -------------------------------------------------------------------------------- /todo-firebase/src/components/task/TodoListItemMenu.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | -------------------------------------------------------------------------------- /todo-firebase/src/components/task/TodoListItemMenuMove.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 35 | -------------------------------------------------------------------------------- /todo-firebase/src/components/user/UserProfile.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /todo-firebase/src/composables/useCredentials.js: -------------------------------------------------------------------------------- 1 | import { ref, reactive } from "vue" 2 | export const useCredentials = () => { 3 | const credentials = reactive({ 4 | email: "", 5 | password: "" 6 | }) 7 | const error = ref(null) 8 | const perform = (callback) => async () => { 9 | try { 10 | error.value = null 11 | await callback() 12 | } catch (e) { 13 | console.log(e) 14 | error.value = e.message 15 | } 16 | } 17 | 18 | return { credentials, error, perform } 19 | } -------------------------------------------------------------------------------- /todo-firebase/src/firebase/project.js: -------------------------------------------------------------------------------- 1 | import { db } from "./firebase" 2 | import { user } from "./user" 3 | import { collection, setDoc, doc, getDoc, getDocs, query, where, orderBy, onSnapshot, addDoc, deleteDoc, runTransaction, serverTimestamp } from "firebase/firestore" 4 | import { ref, onUnmounted, watch } from "vue" 5 | 6 | export const prepareProjectsData = async () => { 7 | const projectsRef = collection(db, "projects") 8 | await Promise.all([ 9 | setDoc(doc(projectsRef, "first"), { 10 | name: "First project", 11 | taskCount: 5, 12 | taskDoneCount: 2 13 | }), 14 | setDoc(doc(projectsRef, "second"), { 15 | name: "Second project", 16 | taskCount: 10, 17 | taskDoneCount: 7 18 | }), 19 | setDoc(doc(projectsRef, "third"), { 20 | name: "Third project", 21 | taskCount: 2, 22 | taskDoneCount: 2 23 | }), 24 | setDoc(doc(projectsRef, "fourth"), { 25 | name: "Fourth project", 26 | taskCount: 4, 27 | taskDoneCount: 3 28 | }), 29 | ]) 30 | console.log('Documents should be added now!'); 31 | } 32 | 33 | export const fetchAllDocuments = async () => { 34 | const projectsRef = collection(db, "projects") 35 | const result = await getDocs(projectsRef) 36 | logResults(result) 37 | } 38 | 39 | export const queryProjects = async () => { 40 | const projectsRef = collection(db, "projects") 41 | const q = query( 42 | projectsRef, 43 | where("taskCount", ">", 2), 44 | where("taskCount", "<=", 6), 45 | orderBy("taskCount"), 46 | // orderBy("taskDoneCount") 47 | ) 48 | const result = await getDocs(q) 49 | logResults(result) 50 | } 51 | 52 | const logResults = (result) => result.forEach( 53 | doc => console.log({ id: doc.id, ...doc.data() }) 54 | ) 55 | 56 | export const fetchSingleDocument = async () => { 57 | const docRef = doc(db, "projects", "first") 58 | const projectDoc = await getDoc(docRef) 59 | 60 | if (projectDoc.exists()) { 61 | console.log({ 62 | id: projectDoc.id, 63 | ...projectDoc.data() 64 | }) 65 | } else { 66 | console.log(`The document does not exist!`) 67 | } 68 | } 69 | 70 | export const watchDocument = async () => { 71 | return onSnapshot( 72 | doc(db, "projects", "first"), 73 | (doc) => console.log(doc.data()) 74 | ) 75 | } 76 | 77 | export const watchProjectsWithDoneTasks = async () => { 78 | const q = query( 79 | collection(db, "projects"), 80 | where("taskDoneCount", ">", 0) 81 | ) 82 | return onSnapshot( 83 | q, 84 | (querySnapshot) => logResults(querySnapshot) 85 | ) 86 | } 87 | 88 | export const useQueryProjects = () => { 89 | const projects = ref([]) 90 | let unsub = () => { } 91 | 92 | watch(user, (user) => { 93 | if (!user || !user.uid) { 94 | return 95 | } 96 | 97 | const q = query( 98 | collection(db, "projects"), 99 | where("uid", "==", user.uid) 100 | ) 101 | unsub() 102 | unsub = onSnapshot(q, (snapshot) => { 103 | projects.value = snapshot.docs.map( 104 | doc => ({ 105 | id: doc.id, 106 | ...doc.data() 107 | }) 108 | ) 109 | }) 110 | }) 111 | onUnmounted(() => { unsub(); console.log(`Unsub projects...`) }) 112 | 113 | return projects 114 | } 115 | 116 | export const useQueryTasks = (projectId) => { 117 | const taskList = ref([]) 118 | let unsub = () => { } 119 | 120 | watch(projectId, (projectId, oldProjectId) => { 121 | if (projectId === null || projectId === undefined) { 122 | console.log(`projectId was nullish`) 123 | taskList.value = [] 124 | return 125 | } 126 | 127 | console.log(`Not watching ${oldProjectId} tasks anymore...`) 128 | unsub() 129 | const q = query( 130 | collection(db, "projects", projectId, "tasks"), 131 | orderBy("timestamp", "desc") 132 | ) 133 | console.log(`Watching ${projectId} tasks!`) 134 | unsub = onSnapshot(q, (snapshot) => { 135 | console.log(`Got ${snapshot.docs.length} tasks...`) 136 | taskList.value = snapshot.docs.map( 137 | doc => ({ 138 | id: doc.id, 139 | ...doc.data() 140 | }) 141 | ) 142 | }) 143 | }) 144 | onUnmounted(() => { unsub(); console.log(`Unsub tasks...`) }) 145 | 146 | return taskList 147 | } 148 | 149 | export const addProject = async (name = "") => { 150 | if (!user?.value) { 151 | return 152 | } 153 | 154 | const project = await addDoc( 155 | collection(db, "projects"), 156 | { 157 | name, 158 | taskCount: 1, 159 | taskDoneCount: 0, 160 | uid: user.value.uid 161 | } 162 | ) 163 | await addDoc( 164 | collection(db, "projects", project.id, "tasks"), 165 | { 166 | description: "First task", 167 | done: false, 168 | priority: false, 169 | timestamp: serverTimestamp(), 170 | uid: user.value.uid 171 | } 172 | ) 173 | 174 | return project 175 | } 176 | 177 | // export const deleteTask = async (projectId, taskId) => { 178 | // await deleteDoc( 179 | // doc(db, "projects", projectId, "tasks", taskId) 180 | // ) 181 | // } 182 | 183 | const getProjectInTransaction = async (transaction, projectId) => { 184 | const projectDocRef = doc( 185 | db, "projects", projectId 186 | ) 187 | const projectDoc = await transaction.get( 188 | projectDocRef 189 | ) 190 | 191 | if (!projectDoc.exists()) { 192 | throw "Project does not exist" 193 | } 194 | 195 | return { 196 | projectDocRef, 197 | projectDoc, 198 | projectData: projectDoc.data() 199 | } 200 | } 201 | 202 | const getTaskInTransaction = async ( 203 | transaction, projectId, taskId 204 | ) => { 205 | const taskDocRef = doc( 206 | db, "projects", projectId, "tasks", taskId 207 | ) 208 | const taskDoc = await transaction.get(taskDocRef) 209 | 210 | if (!taskDoc.exists()) { 211 | throw `Task does not exist` 212 | } 213 | 214 | return { 215 | taskDocRef, 216 | taskDoc, 217 | taskData: taskDoc.data() 218 | } 219 | } 220 | 221 | export const addTask = async (projectId, task) => { 222 | await runTransaction(db, async (transaction) => { 223 | const { projectDocRef, projectData } 224 | = await getProjectInTransaction( 225 | transaction, projectId 226 | ) 227 | 228 | const taskCount = projectData.taskCount + 1 229 | const taskDocRef = doc( 230 | collection(db, "projects", projectId, "tasks") 231 | ) 232 | transaction.set(taskDocRef, { 233 | timestamp: serverTimestamp(), 234 | uid: user.value.uid, 235 | ...task 236 | }) 237 | transaction.update(projectDocRef, { taskCount }) 238 | }) 239 | } 240 | 241 | export const updateTask = async (projectId, task) => { 242 | await runTransaction(db, async (transaction) => { 243 | const { projectDocRef, projectDoc, projectData } 244 | = await getProjectInTransaction( 245 | transaction, projectId 246 | ) 247 | const { taskDocRef, taskData } = await getTaskInTransaction( 248 | transaction, projectId, task.id 249 | ) 250 | let taskDoneCount = projectData.taskDoneCount 251 | 252 | if (true === task.done && !taskData.done) { 253 | taskDoneCount++ 254 | } else if (false === task.done && taskData.done) { 255 | taskDoneCount-- 256 | } 257 | 258 | const { id, ...data } = task 259 | transaction.update(taskDocRef, data) 260 | transaction.update(projectDocRef, { taskDoneCount }) 261 | }) 262 | } 263 | 264 | export const deleteTask = async (projectId, taskId) => { 265 | await runTransaction(db, async (transaction) => { 266 | const { projectDocRef, projectData } 267 | = await getProjectInTransaction( 268 | transaction, projectId 269 | ) 270 | const { taskDocRef, taskData } = await getTaskInTransaction( 271 | transaction, projectId, taskId 272 | ) 273 | const taskCount = projectData.taskCount - 1 274 | const taskDoneCount = projectData.taskDoneCount 275 | - (taskData.done ? 1 : 0) 276 | 277 | transaction.delete(taskDocRef) 278 | transaction.update(projectDocRef, { taskCount, taskDoneCount }) 279 | }) 280 | } 281 | 282 | export const moveTask = async ( 283 | fromProjectId, toProjectId, taskId 284 | ) => { 285 | await runTransaction(db, async (transaction) => { 286 | const { projectDocRef: fromRef, projectData: fromData } 287 | = await getProjectInTransaction( 288 | transaction, fromProjectId 289 | ) 290 | const { projectDocRef: toRef, projectData: toData } 291 | = await getProjectInTransaction( 292 | transaction, toProjectId 293 | ) 294 | const { taskDocRef, taskData } = await getTaskInTransaction( 295 | transaction, fromProjectId, taskId 296 | ) 297 | 298 | transaction.update(fromRef, { 299 | taskCount: fromData.taskCount - 1, 300 | taskDoneCount: fromData.taskDoneCount - 301 | (taskData.done ? 1 : 0) 302 | }) 303 | transaction.update(toRef, { 304 | taskCount: toData.taskCount + 1, 305 | taskDoneCount: toData.taskDoneCount + 306 | (taskData.done ? 1 : 0) 307 | }) 308 | 309 | const newTaskDocRef = doc( 310 | collection( 311 | db, "projects", toProjectId, "tasks" 312 | ) 313 | ) 314 | transaction.set(newTaskDocRef, taskData) 315 | transaction.delete(taskDocRef) 316 | }) 317 | } -------------------------------------------------------------------------------- /todo-firebase/src/firebase/user.js: -------------------------------------------------------------------------------- 1 | import { onSnapshot, doc, updateDoc, setDoc } from "firebase/firestore" 2 | import { ref, onUnmounted, watch } from "vue" 3 | import { db } from "./firebase" 4 | import { getAuth, onAuthStateChanged, signInWithEmailAndPassword, signOut, createUserWithEmailAndPassword } from "firebase/auth" 5 | 6 | export const user = ref(null) 7 | 8 | const auth = getAuth() 9 | onAuthStateChanged(auth, (data) => { 10 | if (data) { 11 | user.value = data 12 | } else { 13 | user.value = null 14 | } 15 | 16 | console.log(user.value) 17 | }) 18 | 19 | export const login = async (email, password) => { 20 | return await signInWithEmailAndPassword( 21 | auth, 22 | email, 23 | password 24 | ) 25 | } 26 | 27 | export const createUser = async (email, password) => { 28 | const result = await createUserWithEmailAndPassword( 29 | auth, email, password 30 | ) 31 | await setDoc( 32 | doc(db, "profiles", result.user.uid), 33 | {} 34 | ) 35 | } 36 | 37 | export const logout = async () => { 38 | await signOut(auth) 39 | } 40 | 41 | export const useUserProfile = () => { 42 | const userProfile = ref({}) 43 | let unsub = () => { } 44 | watch(user, (user) => { 45 | if (!user || !user.uid) { 46 | return 47 | } 48 | 49 | unsub() 50 | unsub = onSnapshot( 51 | doc(db, "profiles", user.uid), 52 | (doc) => userProfile.value = doc.data() 53 | ) 54 | }) 55 | 56 | onUnmounted(() => { unsub(); console.log(`Unsub user...`) }) 57 | return userProfile 58 | } 59 | 60 | export const setActiveProjectId = 61 | async (activeProjectId) => updateDoc( 62 | doc(db, "profiles", user?.value?.uid), 63 | { 64 | activeProjectId 65 | } 66 | ) 67 | 68 | -------------------------------------------------------------------------------- /todo-firebase/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .fade-02-enter-from, 6 | .fade-02-leave-to { 7 | opacity: 0; 8 | } 9 | 10 | .fade-02-enter-to, 11 | .fade-02-leave-from { 12 | opacity: 1; 13 | } 14 | 15 | .fade-02-enter-active, 16 | .fade-02-leave-active { 17 | transition: opacity 0.2s 18 | } -------------------------------------------------------------------------------- /todo-firebase/src/landing.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import Landing from "./Landing.vue"; 3 | 4 | createApp(Landing).mount("#app"); 5 | -------------------------------------------------------------------------------- /todo-firebase/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue" 2 | import App from "./App.vue" 3 | import store from "./store" 4 | import router from "./router" 5 | import "./index.css" 6 | 7 | const app = createApp(App) 8 | app.config.unwrapInjectedRef = true 9 | app.use(store) 10 | app.use(router) 11 | app.mount("#app") 12 | -------------------------------------------------------------------------------- /todo-firebase/src/pages/LoginPage.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | -------------------------------------------------------------------------------- /todo-firebase/src/pages/ProjectPage.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 93 | 94 | -------------------------------------------------------------------------------- /todo-firebase/src/pages/SignupPage.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | -------------------------------------------------------------------------------- /todo-firebase/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from "vue-router" 2 | const routes = [ 3 | { 4 | path: "/", 5 | name: "project", 6 | component: () => import("./../pages/ProjectPage.vue") 7 | }, 8 | { 9 | path: "/login", 10 | name: "login", 11 | component: () => import("./../pages/LoginPage.vue") 12 | }, 13 | { 14 | path: "/signup", 15 | name: "signup", 16 | component: () => import("./../pages/SignupPage.vue") 17 | } 18 | ] 19 | 20 | const router = createRouter({ 21 | history: createWebHashHistory(), 22 | routes 23 | }) 24 | 25 | export default router -------------------------------------------------------------------------------- /todo-firebase/src/store/actions-types.js: -------------------------------------------------------------------------------- 1 | export const MOVE_TASK = "MOVE_TASK"; 2 | -------------------------------------------------------------------------------- /todo-firebase/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | // import { localStoragePlugin } from "./plugins/localStorage"; 3 | import application from "./modules/application"; 4 | import project from "./modules/project"; 5 | 6 | const store = createStore({ 7 | modules: { 8 | project, 9 | application, 10 | }, 11 | state() { 12 | return {}; 13 | }, 14 | getters: {}, 15 | mutations: {}, 16 | actions: {}, 17 | // plugins: [localStoragePlugin], 18 | }); 19 | 20 | export default store; 21 | -------------------------------------------------------------------------------- /todo-firebase/src/store/modules/application.js: -------------------------------------------------------------------------------- 1 | import { SET_ONLY_PENDING } from "./../mutation-types"; 2 | 3 | const state = () => ({ 4 | onlyPending: false, 5 | }); 6 | 7 | const mutations = { 8 | [SET_ONLY_PENDING](state, payload) { 9 | state.onlyPending = payload; 10 | }, 11 | }; 12 | 13 | export default { 14 | namespaced: true, 15 | state, 16 | mutations, 17 | }; 18 | -------------------------------------------------------------------------------- /todo-firebase/src/store/modules/project.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_TASK, 3 | REMOVE_TASK, 4 | UPDATE_TASK, 5 | SET_ACTIVE_PROJECT, 6 | } from "./../mutation-types"; 7 | import { MOVE_TASK } from "./../actions-types"; 8 | 9 | function getProjectById(state, id) { 10 | return state.projects.find((project) => project.id === id); 11 | } 12 | 13 | function getProjectAndTaskIndex(state, { projectId, taskId }) { 14 | const project = getProjectById(state, projectId); 15 | 16 | return { 17 | project, 18 | taskIndex: project?.tasks?.findIndex((task) => task.id === taskId), 19 | }; 20 | } 21 | 22 | const state = () => ({ 23 | activeProjectId: 1, 24 | projects: [ 25 | { 26 | id: 1, 27 | name: "First Project", 28 | tasks: [ 29 | { 30 | id: 1, 31 | description: "Buy food for the dog", 32 | priority: false, 33 | done: false, 34 | }, 35 | { 36 | id: 2, 37 | description: "Pay the bills", 38 | priority: true, 39 | done: false, 40 | }, 41 | { 42 | id: 3, 43 | description: "Buy some computer games", 44 | priority: false, 45 | done: false, 46 | }, 47 | { 48 | id: 4, 49 | description: "Go to the gym", 50 | priority: false, 51 | done: false, 52 | }, 53 | ], 54 | }, 55 | { 56 | id: 2, 57 | name: "Life Project", 58 | tasks: [ 59 | { 60 | id: 101, 61 | description: "Visit parents", 62 | priority: false, 63 | done: false, 64 | }, 65 | { 66 | id: 102, 67 | description: "Visit uncles", 68 | priority: true, 69 | done: false, 70 | }, 71 | { 72 | id: 103, 73 | description: "Go around the world", 74 | priority: false, 75 | done: false, 76 | }, 77 | { 78 | id: 104, 79 | description: "Quit smoking", 80 | priority: false, 81 | done: false, 82 | }, 83 | ], 84 | }, 85 | ], 86 | }); 87 | const getters = { 88 | activeProject(state) { 89 | return getProjectById(state, state.activeProjectId); 90 | }, 91 | projectsWithStats(state) { 92 | return state.projects.map((project) => ({ 93 | id: project.id, 94 | ...project, 95 | notDoneCount: project.tasks.filter((task) => !task.done).length, 96 | })); 97 | }, 98 | activeProjectTasks(_, getters) { 99 | return getters.activeProject?.tasks ?? []; 100 | }, 101 | }; 102 | const mutations = { 103 | /* 104 | payload: { 105 | projectId: number, 106 | task: { 107 | id: number, 108 | description: string, 109 | done: boolean, 110 | priority: boolean, 111 | } 112 | } 113 | */ 114 | [ADD_TASK](state, payload) { 115 | getProjectById(state, payload.projectId)?.tasks.push(payload.task); 116 | }, 117 | [REMOVE_TASK](state, payload) { 118 | const { project, taskIndex } = getProjectAndTaskIndex(state, payload); 119 | 120 | if (taskIndex !== undefined && taskIndex !== -1) { 121 | project.tasks.splice(taskIndex, 1); 122 | } 123 | }, 124 | [UPDATE_TASK](state, payload) { 125 | const { project, taskIndex } = getProjectAndTaskIndex(state, payload); 126 | 127 | if (taskIndex !== undefined && taskIndex !== -1) { 128 | project.tasks[taskIndex] = payload.task; 129 | } 130 | }, 131 | [SET_ACTIVE_PROJECT](state, activeProjectId) { 132 | state.activeProjectId = activeProjectId; 133 | }, 134 | }; 135 | const actions = { 136 | [MOVE_TASK]({ commit, state }, { taskId, fromProjectId, toProjectId }) { 137 | const { project, taskIndex } = getProjectAndTaskIndex(state, { 138 | taskId, 139 | projectId: fromProjectId, 140 | }); 141 | commit(ADD_TASK, { 142 | task: project.tasks[taskIndex], 143 | projectId: toProjectId, 144 | }); 145 | commit(REMOVE_TASK, { 146 | taskId, 147 | projectId: fromProjectId, 148 | }); 149 | }, 150 | }; 151 | 152 | export default { 153 | namespaced: true, 154 | state, 155 | getters, 156 | mutations, 157 | actions, 158 | }; 159 | -------------------------------------------------------------------------------- /todo-firebase/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ADD_TASK = "ADD_TASK"; 2 | export const REMOVE_TASK = "REMOVE_TASK"; 3 | export const UPDATE_TASK = "UPDATE_TASK"; 4 | export const SET_ONLY_PENDING = "SET_ONLY_PENDING"; 5 | export const SET_ACTIVE_PROJECT = "SET_ACTIVE_PROJECT"; 6 | -------------------------------------------------------------------------------- /todo-firebase/src/store/plugins/localStorage.js: -------------------------------------------------------------------------------- 1 | const KEY = "vuex-storage"; 2 | 3 | export const localStoragePlugin = (store) => { 4 | console.log("Plugin was initialized"); 5 | store.replaceState( 6 | Object.assign(store.state, JSON.parse(window.localStorage.getItem(KEY))) 7 | ); 8 | 9 | store.subscribe((mutation, state) => { 10 | console.log(mutation); 11 | window.localStorage.setItem(KEY, JSON.stringify(state)); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /todo-firebase/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 3 | theme: { 4 | extend: {}, 5 | }, 6 | plugins: [], 7 | } 8 | -------------------------------------------------------------------------------- /todo-firebase/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /transitions-animations/transition-group/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /transitions-animations/transition-group/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /transitions-animations/transition-group/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transition-group", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.25" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^2.3.0", 15 | "vite": "^2.9.0" 16 | } 17 | } -------------------------------------------------------------------------------- /transitions-animations/transition-group/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/transitions-animations/transition-group/public/favicon.ico -------------------------------------------------------------------------------- /transitions-animations/transition-group/src/App.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 37 | 38 | 61 | -------------------------------------------------------------------------------- /transitions-animations/transition-group/src/components/ListItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /transitions-animations/transition-group/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /transitions-animations/transition-group/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /transitions-animations/transition/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /transitions-animations/transition/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /transitions-animations/transition/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-animations", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "vue": "^3.2.25" 12 | }, 13 | "devDependencies": { 14 | "@vitejs/plugin-vue": "^2.3.0", 15 | "vite": "^2.9.0" 16 | } 17 | } -------------------------------------------------------------------------------- /transitions-animations/transition/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/transitions-animations/transition/public/favicon.ico -------------------------------------------------------------------------------- /transitions-animations/transition/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 24 | -------------------------------------------------------------------------------- /transitions-animations/transition/src/Fade.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /transitions-animations/transition/src/FadeTransition.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /transitions-animations/transition/src/Heart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 85 | -------------------------------------------------------------------------------- /transitions-animations/transition/src/TransitionBetween.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 19 | 20 | -------------------------------------------------------------------------------- /transitions-animations/transition/src/main.css: -------------------------------------------------------------------------------- 1 | .fade-enter-active, 2 | .fade-leave-active { 3 | transition: opacity 2s ease; 4 | } 5 | 6 | .fade-enter-from, 7 | .fade-leave-to { 8 | opacity: 0; 9 | } 10 | 11 | .fade-enter-to, 12 | .fade-leave-from { 13 | opacity: 0.5; 14 | } -------------------------------------------------------------------------------- /transitions-animations/transition/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import './main.css' 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /transitions-animations/transition/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | -------------------------------------------------------------------------------- /transitions-animations/transitions-animations.html: -------------------------------------------------------------------------------- 1 | 102 | 103 |
104 | 107 |
108 | 109 |
110 |

linear

111 |
112 |
113 | 114 |
115 |

ease out

116 |
117 |
118 | 119 |
120 |

ease-in

121 |
122 |
123 | 124 |
125 |

ease-in-out

126 |
127 |
128 | 129 |
130 |

ease

131 |
132 |
133 | 134 |
135 |

:hover trigerring transition

136 |

Different speed of transitions

137 | 138 |
139 | 140 |
141 |

cubic-bezier

142 |
143 |
144 | 145 |
146 |

Animation

147 |
148 | ♥️ 149 |
150 |
151 | 152 | -------------------------------------------------------------------------------- /vuex/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /vuex/.env.development: -------------------------------------------------------------------------------- 1 | API_URL=http://localhost:8080/api -------------------------------------------------------------------------------- /vuex/.env.production: -------------------------------------------------------------------------------- 1 | API_URL=http://api.yourdomain.com/api -------------------------------------------------------------------------------- /vuex/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"], 7 | parserOptions: { 8 | parser: "babel-eslint", 9 | }, 10 | rules: { 11 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 12 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /vuex/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /vuex/README.md: -------------------------------------------------------------------------------- 1 | # sfc 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /vuex/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /vuex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sfc", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^3.0.0", 13 | "vuex": "^4.0.2" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "~4.5.0", 17 | "@vue/cli-plugin-eslint": "~4.5.0", 18 | "@vue/cli-service": "~4.5.0", 19 | "@vue/compiler-sfc": "^3.0.0", 20 | "@vue/eslint-config-prettier": "^6.0.0", 21 | "babel-eslint": "^10.1.0", 22 | "eslint": "^6.7.2", 23 | "eslint-plugin-prettier": "^3.3.1", 24 | "eslint-plugin-vue": "^7.0.0", 25 | "prettier": "^2.2.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vuex/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piotr-jura-udemy/vue-course/b3d387aab6531683fd742b56214a1fff52d3e89d/vuex/public/favicon.ico -------------------------------------------------------------------------------- /vuex/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 12 | 13 | <%= htmlWebpackPlugin.options.title %> 14 | 15 | 16 | 17 | 18 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /vuex/src/App.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 127 | -------------------------------------------------------------------------------- /vuex/src/Landing.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /vuex/src/components/base/BaseCheckbox.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 31 | -------------------------------------------------------------------------------- /vuex/src/components/base/BaseSmallListButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /vuex/src/components/base/BaseTextButton.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /vuex/src/components/project/ProjectList.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | -------------------------------------------------------------------------------- /vuex/src/components/project/ProjectListItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 33 | -------------------------------------------------------------------------------- /vuex/src/components/project/ProjectSummaryLine.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 43 | -------------------------------------------------------------------------------- /vuex/src/components/task/AddTaskInput.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 31 | -------------------------------------------------------------------------------- /vuex/src/components/task/TodoListItem.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 50 | -------------------------------------------------------------------------------- /vuex/src/components/task/TodoListItemMenu.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /vuex/src/components/task/TodoListItemMenuMove.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /vuex/src/landing.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import Landing from "./Landing.vue"; 3 | 4 | createApp(Landing).mount("#app"); 5 | -------------------------------------------------------------------------------- /vuex/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | import store from "./store"; 4 | 5 | const app = createApp(App); 6 | app.config.unwrapInjectedRef = true; 7 | app.use(store); 8 | app.mount("#app"); 9 | -------------------------------------------------------------------------------- /vuex/src/store/actions-types.js: -------------------------------------------------------------------------------- 1 | export const MOVE_TASK = "MOVE_TASK"; -------------------------------------------------------------------------------- /vuex/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "vuex"; 2 | // import { localStoragePlugin } from "./plugins/localStorage"; 3 | import application from "./modules/application"; 4 | import project from "./modules/project"; 5 | 6 | const store = createStore({ 7 | modules: { 8 | project, 9 | application 10 | }, 11 | state() { 12 | return {}; 13 | }, 14 | getters: {}, 15 | mutations: {}, 16 | actions: {}, 17 | // plugins: [localStoragePlugin], 18 | }); 19 | 20 | export default store; 21 | -------------------------------------------------------------------------------- /vuex/src/store/modules/application.js: -------------------------------------------------------------------------------- 1 | import { SET_ONLY_PENDING } from "./../mutation-types"; 2 | 3 | const state = () => ({ 4 | onlyPending: false, 5 | }); 6 | 7 | const mutations = { 8 | [SET_ONLY_PENDING](state, payload) { 9 | state.onlyPending = payload; 10 | }, 11 | }; 12 | 13 | export default { 14 | namespaced: true, 15 | state, mutations, 16 | } -------------------------------------------------------------------------------- /vuex/src/store/modules/project.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_TASK, 3 | REMOVE_TASK, 4 | UPDATE_TASK, 5 | SET_ACTIVE_PROJECT, 6 | } from "./../mutation-types"; 7 | import { MOVE_TASK } from "./../actions-types"; 8 | 9 | function getProjectById(state, id) { 10 | return state.projects.find( 11 | (project) => project.id === id 12 | ); 13 | } 14 | 15 | function getProjectAndTaskIndex( 16 | state, { projectId, taskId } 17 | ) { 18 | const project = getProjectById(state, projectId); 19 | 20 | return { 21 | project, 22 | taskIndex: project?.tasks?.findIndex( 23 | (task) => task.id === taskId 24 | ) 25 | } 26 | } 27 | 28 | const state = () => ({ 29 | activeProjectId: 1, 30 | projects: [ 31 | { 32 | id: 1, 33 | name: "First Project", 34 | tasks: [ 35 | { 36 | id: 1, 37 | description: "Buy food for the dog", 38 | priority: false, 39 | done: false, 40 | }, 41 | { 42 | id: 2, 43 | description: "Pay the bills", 44 | priority: true, 45 | done: false, 46 | }, 47 | { 48 | id: 3, 49 | description: "Buy some computer games", 50 | priority: false, 51 | done: false, 52 | }, 53 | { 54 | id: 4, 55 | description: "Go to the gym", 56 | priority: false, 57 | done: false, 58 | }, 59 | ], 60 | }, 61 | { 62 | id: 2, 63 | name: "Life Project", 64 | tasks: [ 65 | { 66 | id: 101, 67 | description: "Visit parents", 68 | priority: false, 69 | done: false, 70 | }, 71 | { 72 | id: 102, 73 | description: "Visit uncles", 74 | priority: true, 75 | done: false, 76 | }, 77 | { 78 | id: 103, 79 | description: "Go around the world", 80 | priority: false, 81 | done: false, 82 | }, 83 | { 84 | id: 104, 85 | description: "Quit smoking", 86 | priority: false, 87 | done: false, 88 | }, 89 | ], 90 | }, 91 | ], 92 | }); 93 | const getters = { 94 | activeProject(state) { 95 | return getProjectById(state, state.activeProjectId); 96 | }, 97 | projectsWithStats(state) { 98 | return state.projects.map((project) => ({ 99 | id: project.id, 100 | ...project, 101 | notDoneCount: project.tasks.filter( 102 | (task) => !task.done 103 | ).length, 104 | })); 105 | }, 106 | activeProjectTasks(_, getters) { 107 | return getters.activeProject?.tasks ?? []; 108 | }, 109 | }; 110 | const mutations = { 111 | /* 112 | payload: { 113 | projectId: number, 114 | task: { 115 | id: number, 116 | description: string, 117 | done: boolean, 118 | priority: boolean, 119 | } 120 | } 121 | */ 122 | [ADD_TASK](state, payload) { 123 | getProjectById( 124 | state, payload.projectId 125 | )?.tasks.push(payload.task); 126 | }, 127 | [REMOVE_TASK](state, payload) { 128 | const { project, taskIndex } = getProjectAndTaskIndex( 129 | state, payload 130 | ); 131 | 132 | if (taskIndex !== undefined && taskIndex !== -1) { 133 | project.tasks.splice(taskIndex, 1); 134 | } 135 | }, 136 | [UPDATE_TASK](state, payload) { 137 | const { project, taskIndex } = getProjectAndTaskIndex( 138 | state, payload 139 | ); 140 | 141 | if (taskIndex !== undefined && taskIndex !== -1) { 142 | project.tasks[taskIndex] = payload.task; 143 | } 144 | }, 145 | [SET_ACTIVE_PROJECT](state, activeProjectId) { 146 | state.activeProjectId = activeProjectId; 147 | }, 148 | }; 149 | const actions = { 150 | [MOVE_TASK]({ commit, state }, { taskId, fromProjectId, toProjectId }) { 151 | const { project, taskIndex } = getProjectAndTaskIndex( 152 | state, { taskId, projectId: fromProjectId } 153 | ); 154 | commit(ADD_TASK, { 155 | task: project.tasks[taskIndex], 156 | projectId: toProjectId, 157 | }); 158 | commit(REMOVE_TASK, { 159 | taskId, 160 | projectId: fromProjectId 161 | }); 162 | } 163 | }; 164 | 165 | export default { 166 | namespaced: true, 167 | state, getters, mutations, actions 168 | } -------------------------------------------------------------------------------- /vuex/src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ADD_TASK = "ADD_TASK"; 2 | export const REMOVE_TASK = "REMOVE_TASK"; 3 | export const UPDATE_TASK = "UPDATE_TASK"; 4 | export const SET_ONLY_PENDING = "SET_ONLY_PENDING"; 5 | export const SET_ACTIVE_PROJECT = "SET_ACTIVE_PROJECT"; 6 | -------------------------------------------------------------------------------- /vuex/src/store/plugins/localStorage.js: -------------------------------------------------------------------------------- 1 | const KEY = "vuex-storage"; 2 | 3 | export const localStoragePlugin = (store) => { 4 | console.log("Plugin was initialized"); 5 | store.replaceState( 6 | Object.assign(store.state, JSON.parse(window.localStorage.getItem(KEY))) 7 | ); 8 | 9 | store.subscribe((mutation, state) => { 10 | console.log(mutation); 11 | window.localStorage.setItem(KEY, JSON.stringify(state)); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /vuex/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: process.env.NODE_ENV === "production" ? "/app" : "", 3 | pages: { 4 | index: { 5 | title: "Todo Applicaiton", 6 | entry: "/src/main.js", 7 | }, 8 | landing: { 9 | title: "Landing Page", 10 | entry: "/src/landing.js", 11 | }, 12 | }, 13 | }; 14 | --------------------------------------------------------------------------------