From 5d3af5d36581bc2d7e9010673e8afe4b5a54d984 Mon Sep 17 00:00:00 2001
From: w3bdesign <45217974+w3bdesign@users.noreply.github.com>
Date: Wed, 27 Jan 2021 00:33:47 +0100
Subject: [PATCH] Start work on design and layout with Vue Router
Added Vue Router
---
package-lock.json | 148 +-
package.json | 3 +-
public/js/app.js | 3564 ++++++++++++++++-
resources/js/app.js | 19 +-
resources/js/components/Footer/Footer.vue | 13 +
resources/js/components/Header/Layout.vue | 18 +
resources/js/components/Header/MobileMenu.vue | 7 +
resources/js/components/Header/Navbar.vue | 122 +-
resources/js/components/Layouts/Layout.vue | 14 +
resources/js/components/Products/Products.vue | 7 +
10 files changed, 3751 insertions(+), 164 deletions(-)
create mode 100644 resources/js/components/Footer/Footer.vue
create mode 100644 resources/js/components/Header/Layout.vue
create mode 100644 resources/js/components/Header/MobileMenu.vue
create mode 100644 resources/js/components/Layouts/Layout.vue
create mode 100644 resources/js/components/Products/Products.vue
diff --git a/package-lock.json b/package-lock.json
index e991a9c3..98f98f90 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1173,10 +1173,13 @@
}
},
"@types/browserslist": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/@types/browserslist/-/browserslist-4.8.0.tgz",
- "integrity": "sha512-4PyO9OM08APvxxo1NmQyQKlJdowPCOQIy5D/NLO3aO0vGC57wsMptvGp3b8IbYnupFZr92l1dlVief1JvS6STQ==",
- "dev": true
+ "version": "4.15.0",
+ "resolved": "https://registry.npmjs.org/@types/browserslist/-/browserslist-4.15.0.tgz",
+ "integrity": "sha512-h9LyKErRGZqMsHh9bd+FE8yCIal4S0DxKTOeui56VgVXqa66TKiuaIUxCAI7c1O0LjaUzOTcsMyOpO9GetozRA==",
+ "dev": true,
+ "requires": {
+ "browserslist": "*"
+ }
},
"@types/clean-css": {
"version": "4.2.3",
@@ -1254,9 +1257,9 @@
}
},
"@types/estree": {
- "version": "0.0.45",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz",
- "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==",
+ "version": "0.0.46",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
+ "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==",
"dev": true
},
"@types/glob": {
@@ -1325,9 +1328,9 @@
}
},
"@types/json-schema": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
- "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
+ "version": "7.0.7",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
+ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
"dev": true
},
"@types/micromatch": {
@@ -1352,9 +1355,9 @@
"dev": true
},
"@types/node": {
- "version": "14.14.21",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz",
- "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==",
+ "version": "14.14.22",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
+ "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==",
"dev": true
},
"@types/parse-glob": {
@@ -1680,6 +1683,12 @@
"@xtuc/long": "4.2.2"
}
},
+ "@webpack-cli/configtest": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.0.tgz",
+ "integrity": "sha512-Un0SdBoN1h4ACnIO7EiCjWuyhNI0Jl96JC+63q6xi4HDUYRZn8Auluea9D+v9NWKc5J4sICVEltdBaVjLX39xw==",
+ "dev": true
+ },
"@webpack-cli/info": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz",
@@ -1690,9 +1699,9 @@
}
},
"@webpack-cli/serve": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz",
- "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.2.tgz",
+ "integrity": "sha512-03GkWxcgFfm8+WIwcsqJb9agrSDNDDoxaNnexPnCCexP5SCE4IgFd9lNpSy+K2nFqVMpgTFw6SwbmVAVTndVew==",
"dev": true
},
"@xtuc/ieee754": {
@@ -1718,9 +1727,9 @@
}
},
"acorn": {
- "version": "8.0.4",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz",
- "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==",
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.5.tgz",
+ "integrity": "sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==",
"dev": true
},
"acorn-node": {
@@ -1991,13 +2000,13 @@
"dev": true
},
"autoprefixer": {
- "version": "10.2.1",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.1.tgz",
- "integrity": "sha512-dwP0UjyYvROUvtU+boBx8ff5pPWami1NGTrJs9YUsS/oZVbRAcdNHOOuXSA1fc46tgKqe072cVaKD69rvCc3QQ==",
+ "version": "10.2.3",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.3.tgz",
+ "integrity": "sha512-vlz+iv+EnLkVaTgX8wApfYzmK3LUfK8Z9XAnmflzxMy/+oFuNK8fVGQV79SOpBv4jxk2YQJimw4hXIKZ29570A==",
"dev": true,
"requires": {
"browserslist": "^4.16.1",
- "caniuse-lite": "^1.0.30001173",
+ "caniuse-lite": "^1.0.30001178",
"colorette": "^1.2.1",
"fraction.js": "^4.0.13",
"normalize-range": "^0.1.2",
@@ -2498,9 +2507,9 @@
}
},
"caniuse-lite": {
- "version": "1.0.30001178",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001178.tgz",
- "integrity": "sha512-VtdZLC0vsXykKni8Uztx45xynytOi71Ufx9T8kHptSw9AL4dpqailUJJHavttuzUe1KYuBYtChiWv+BAb7mPmQ==",
+ "version": "1.0.30001179",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz",
+ "integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA==",
"dev": true
},
"chalk": {
@@ -2963,12 +2972,12 @@
"dev": true
},
"core-js-compat": {
- "version": "3.8.2",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.2.tgz",
- "integrity": "sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ==",
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz",
+ "integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==",
"dev": true,
"requires": {
- "browserslist": "^4.16.0",
+ "browserslist": "^4.16.1",
"semver": "7.0.0"
},
"dependencies": {
@@ -3799,9 +3808,9 @@
"dev": true
},
"electron-to-chromium": {
- "version": "1.3.641",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.641.tgz",
- "integrity": "sha512-b0DLhsHSHESC1I+Nx6n4w4Lr61chMd3m/av1rZQhS2IXTzaS5BMM5N+ldWdMIlni9CITMRM09m8He4+YV/92TA==",
+ "version": "1.3.645",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.645.tgz",
+ "integrity": "sha512-T7mYop3aDpRHIQaUYcmzmh6j9MAe560n6ukqjJMbVC6bVTau7dSpvB18bcsBPPtOSe10cKxhJFtlbEzLa0LL1g==",
"dev": true
},
"elliptic": {
@@ -3865,9 +3874,9 @@
}
},
"entities": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
- "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
},
"envinfo": {
@@ -4627,9 +4636,9 @@
"dev": true
},
"get-intrinsic": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz",
- "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.0.tgz",
+ "integrity": "sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
@@ -5312,9 +5321,9 @@
"dev": true
},
"ip-regex": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.2.0.tgz",
- "integrity": "sha512-n5cDDeTWWRwK1EBoWwRti+8nP4NbytBBY0pldmnIkq6Z55KNFmWofh4rl9dPZpj+U/nVq7gweR3ylrvMt4YZ5A==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
+ "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
"dev": true
},
"ipaddr.js": {
@@ -5771,9 +5780,9 @@
"dev": true
},
"laravel-mix": {
- "version": "6.0.10",
- "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.10.tgz",
- "integrity": "sha512-wVWpX5I/weqUZDQpVbr3k2pvb1Of2Di/4G5UDIfDiPNOBc4WFp1fvmJV88/H/LZJBncv3VZ+7chzbYMasNzYiw==",
+ "version": "6.0.11",
+ "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.11.tgz",
+ "integrity": "sha512-1M5HSQ80p1e1JW64miAZnPW/Er1k2dQDYk036v58xjgVFUn7dbpFh5j1T6sAYK1tTBpRO9344uPtdruw7yjqLA==",
"dev": true,
"requires": {
"@babel/core": "^7.12.3",
@@ -6753,9 +6762,9 @@
"dev": true
},
"p-retry": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz",
- "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.3.0.tgz",
+ "integrity": "sha512-Pow4yaHpOiJou1QcpGcBJhGHiS4782LdDa6GhU91hlaNh3ExOOupjSJcxPQZYmUSZk3Pl2ARz/LRvW8Qu0+3mQ==",
"dev": true,
"requires": {
"@types/retry": "^0.12.0",
@@ -7376,16 +7385,16 @@
}
},
"postcss-loader": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.1.0.tgz",
- "integrity": "sha512-vbCkP70F3Q9PIk6d47aBwjqAMI4LfkXCoyxj+7NPNuVIwfTGdzv2KVQes59/RuxMniIgsYQCFSY42P3+ykJfaw==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.2.0.tgz",
+ "integrity": "sha512-mqgScxHqbiz1yxbnNcPdKYo/6aVt+XExURmEbQlviFVWogDbM4AJ0A/B+ZBpYsJrTRxKw7HyRazg9x0Q9SWwLA==",
"dev": true,
"requires": {
"cosmiconfig": "^7.0.0",
"klona": "^2.0.4",
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0",
- "semver": "^7.3.2"
+ "semver": "^7.3.4"
},
"dependencies": {
"cosmiconfig": {
@@ -10447,6 +10456,11 @@
}
}
},
+ "vue-router": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.3.tgz",
+ "integrity": "sha512-AD1OjtVPyQHTSpoRsEGfPpxRQwhAhxcacOYO3zJ3KNkYP/r09mileSp6kdMQKhZWP2cFsPR3E2M3PZguSN5/ww=="
+ },
"vuex": {
"version": "4.0.0-rc.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.0-rc.2.tgz",
@@ -10472,13 +10486,13 @@
}
},
"webpack": {
- "version": "5.15.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.15.0.tgz",
- "integrity": "sha512-y/xG+ONDz78yn3VvP6gAvGr1/gkxOgitvHSXBmquyN8KDtrGEyE3K9WkXOPB7QmfcOBCpO4ELXwNcCYQnEmexA==",
+ "version": "5.18.0",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.18.0.tgz",
+ "integrity": "sha512-RmiP/iy6ROvVe/S+u0TrvL/oOmvP+2+Bs8MWjvBwwY/j82Q51XJyDJ75m0QAGntL1Wx6B//Xc0+4VPP/hlNHmw==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.0",
- "@types/estree": "^0.0.45",
+ "@types/estree": "^0.0.46",
"@webassemblyjs/ast": "1.11.0",
"@webassemblyjs/wasm-edit": "1.11.0",
"@webassemblyjs/wasm-parser": "1.11.0",
@@ -10579,14 +10593,15 @@
}
},
"webpack-cli": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz",
- "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.4.0.tgz",
+ "integrity": "sha512-/Qh07CXfXEkMu5S8wEpjuaw2Zj/CC0hf/qbTDp6N8N7JjdGuaOjZ7kttz+zhuJO/J5m7alQEhNk9lsc4rC6xgQ==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "^0.5.0",
+ "@webpack-cli/configtest": "^1.0.0",
"@webpack-cli/info": "^1.2.1",
- "@webpack-cli/serve": "^1.2.1",
+ "@webpack-cli/serve": "^1.2.2",
"colorette": "^1.2.1",
"commander": "^6.2.0",
"enquirer": "^2.3.6",
@@ -10596,18 +10611,7 @@
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"v8-compile-cache": "^2.2.0",
- "webpack-merge": "^4.2.2"
- },
- "dependencies": {
- "webpack-merge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
- "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
- "dev": true,
- "requires": {
- "lodash": "^4.17.15"
- }
- }
+ "webpack-merge": "^5.7.3"
}
},
"webpack-dev-middleware": {
diff --git a/package.json b/package.json
index 301e3a3a..2c7b6653 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
"@vue/compiler-sfc": "^3.0.5",
"axios": "^0.21.1",
"cross-env": "^7.0.3",
- "laravel-mix": "^6.0.10",
+ "laravel-mix": "^6.0.11",
"lodash": "^4.17.20",
"postcss": "^8.2.4",
"resolve-url-loader": "^3.1.2",
@@ -22,6 +22,7 @@
},
"dependencies": {
"vue": "^3.0.5",
+ "vue-router": "^4.0.3",
"vuex": "^4.0.0-rc.2"
}
}
diff --git a/public/js/app.js b/public/js/app.js
index f7e1c2da..a98e7afd 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -16339,6 +16339,21 @@ __webpack_require__.r(__webpack_exports__);
/***/ }),
+/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Products/Products.vue?vue&type=script&lang=js":
+/*!***********************************************************************************************************************************************************************************************************!*\
+ !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Products/Products.vue?vue&type=script&lang=js ***!
+ \***********************************************************************************************************************************************************************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__
+/* harmony export */ });
+/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({});
+
+/***/ }),
+
/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Header/Navbar.vue?vue&type=template&id=41f95097&scoped=true":
/*!***********************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Header/Navbar.vue?vue&type=template&id=41f95097&scoped=true ***!
@@ -16358,42 +16373,89 @@ var _withId = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.withScopeId)("dat
(0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)("data-v-41f95097");
var _hoisted_1 = {
- "class": "text-gray-700 body-font"
+ role: "banner",
+ "class": "container flex flex-col justify-center px-0 pt-6 mx-auto mb-6"
};
var _hoisted_2 = {
- "class": "container flex flex-col flex-wrap items-center p-5 mx-auto md:flex-row"
+ "class": "flex flex-wrap lg:px-4"
+};
+
+var _hoisted_3 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", {
+ "class": "w-9/12 pr-2 my-2 overflow-hidden lg:w-3/12 md:w-10/12"
+}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", {
+ "class": "ml-4 lg:ml-0"
+}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("img", {
+ alt: "Logo",
+ "class": "h-20 lg:h-24",
+ "aria-label": "Nettbutikk logo",
+ src: "https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg"
+})])], -1
+/* HOISTED */
+);
+
+var _hoisted_4 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" MobileMenu ");
+
+var _hoisted_5 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", {
+ "class": "hidden lg:w-1/12 lg:block"
+}, null, -1
+/* HOISTED */
+);
+
+var _hoisted_6 = {
+ id: "nav-content",
+ "class": "hidden w-full mt-4 bg-black lg:w-8/12 lg:block lg:bg-white lg:mt-0 lg:text-right",
+ "aria-expanded": "false"
+};
+var _hoisted_7 = {
+ "class": "px-6 lg:px-0 lg:pt-5 xl:pt-7"
+};
+var _hoisted_8 = {
+ id: "block-main",
+ role: "navigation",
+ "aria-labelledby": "block-main-menu"
+};
+var _hoisted_9 = {
+ "class": "items-center justify-end flex-1 pr-4 -mr-4 list-reset lg:flex"
+};
+var _hoisted_10 = {
+ "class": "inline-block py-2 text-xl font-semibold no-underline lg:text-base lg:px-4"
};
-var _hoisted_3 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("a", {
- "class": "flex items-center mb-4 font-medium text-gray-900 title-font md:mb-0"
-}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("svg", {
- xmlns: "http://www.w3.org/2000/svg",
- fill: "none",
- stroke: "currentColor",
- "stroke-linecap": "round",
- "stroke-linejoin": "round",
- "stroke-width": "2",
- "class": "w-10 h-10 p-2 text-white bg-indigo-500 rounded-full",
- viewBox: "0 0 24 24"
-}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("path", {
- d: "M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"
-})]), /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("span", {
- "class": "ml-3 text-xl"
-}, "Shopping Cart")], -1
+var _hoisted_11 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("span", {
+ "class": "text-xl text-white no-underline lg:text-black is-active"
+}, " Home ", -1
/* HOISTED */
);
-var _hoisted_4 = {
- "class": "flex flex-wrap items-center justify-center text-base md:mr-auto md:ml-4 md:py-1 md:pl-4 md:border-l md:border-gray-400"
+var _hoisted_12 = {
+ "class": "inline-block py-2 text-xl font-semibold no-underline lg:text-base lg:px-4"
};
-var _hoisted_5 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" Products ");
+var _hoisted_13 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("span", {
+ "class": "text-xl text-white no-underline lg:text-black"
+}, "Products", -1
+/* HOISTED */
+);
-var _hoisted_6 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" Checkout");
+var _hoisted_14 = {
+ "class": "inline-block py-2 text-xl font-semibold no-underline lg:text-base lg:px-4"
+};
-var _hoisted_7 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("span", {
- "class": "inline-block ml-1"
-}, null, -1
+var _hoisted_15 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("span", {
+ "class": "text-xl text-white no-underline lg:text-black is-active"
+}, "Categories", -1
+/* HOISTED */
+);
+
+var _hoisted_16 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("li", {
+ "class": "inline-block py-2 text-xl font-semibold no-underline lg:text-base lg:px-4"
+}, " Search ", -1
+/* HOISTED */
+);
+
+var _hoisted_17 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("li", {
+ "class": "inline-block py-2 text-xl font-semibold no-underline lg:text-base lg:px-4"
+}, " Shopping cart ", -1
/* HOISTED */
);
@@ -16402,35 +16464,38 @@ var _hoisted_7 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("
var render = /*#__PURE__*/_withId(function (_ctx, _cache, $props, $setup, $data, $options) {
var _component_router_link = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("router-link");
- return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)("div", null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("header", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_2, [_hoisted_3, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("nav", _hoisted_4, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_router_link, {
- "class": "mr-5 hover:text-gray-900",
- to: {
- name: 'products.index'
- }
+ var _component_router_view = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("router-view");
+
+ return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("header", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_2, [_hoisted_3, _hoisted_4, _hoisted_5, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_6, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_7, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("nav", _hoisted_8, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("ul", _hoisted_9, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("li", _hoisted_10, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_router_link, {
+ to: "/"
}, {
"default": _withId(function () {
- return [_hoisted_5];
+ return [_hoisted_11];
}),
_: 1
/* STABLE */
- }, 8
- /* PROPS */
- , ["to"])]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_router_link, {
- "class": "inline-flex items-center px-3 py-1 mt-4 text-base bg-gray-200 border-0 rounded focus:outline-none hover:bg-gray-300 md:mt-0",
- to: {
- name: 'order.checkout'
- }
+ })]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("li", _hoisted_12, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_router_link, {
+ to: "/products"
+ }, {
+ "default": _withId(function () {
+ return [_hoisted_13];
+ }),
+ _: 1
+ /* STABLE */
+
+ })]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("li", _hoisted_14, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_router_link, {
+ to: "/categories"
}, {
"default": _withId(function () {
- return [_hoisted_6, _hoisted_7];
+ return [_hoisted_15];
}),
_: 1
/* STABLE */
- }, 8
- /* PROPS */
- , ["to"])])])]);
+ })]), _hoisted_16, _hoisted_17])])])])])])]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_router_view)], 64
+ /* STABLE_FRAGMENT */
+ );
});
/***/ }),
@@ -16515,6 +16580,23 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
/***/ }),
+/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Products/Products.vue?vue&type=template&id=4a553918":
+/*!***************************************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Products/Products.vue?vue&type=template&id=4a553918 ***!
+ \***************************************************************************************************************************************************************************************************************************************************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "render": () => /* binding */ render
+/* harmony export */ });
+function render(_ctx, _cache, $props, $setup, $data, $options) {
+ return "Show all products";
+}
+
+/***/ }),
+
/***/ "./resources/js/app.js":
/*!*****************************!*\
!*** ./resources/js/app.js ***!
@@ -16524,18 +16606,37 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.esm-bundler.js");
+/* harmony import */ var vue_router__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! vue-router */ "./node_modules/vue-router/dist/vue-router.esm-bundler.js");
/* harmony import */ var _store_index__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./store/index */ "./resources/js/store/index.js");
/* harmony import */ var _components_MainIndex_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/MainIndex.vue */ "./resources/js/components/MainIndex.vue");
+/* harmony import */ var _components_Header_Navbar_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/Header/Navbar.vue */ "./resources/js/components/Header/Navbar.vue");
+/* harmony import */ var _components_Products_Products_vue__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/Products/Products.vue */ "./resources/js/components/Products/Products.vue");
__webpack_require__(/*! ./bootstrap */ "./resources/js/bootstrap.js");
+
+
+
+var routes = [{
+ path: "/",
+ component: _components_Header_Navbar_vue__WEBPACK_IMPORTED_MODULE_3__.default
+}, {
+ path: "/products",
+ component: _components_Products_Products_vue__WEBPACK_IMPORTED_MODULE_4__.default
+}];
+var router = (0,vue_router__WEBPACK_IMPORTED_MODULE_5__.createRouter)({
+ history: (0,vue_router__WEBPACK_IMPORTED_MODULE_5__.createWebHashHistory)(),
+ routes: routes
+});
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createApp)({
components: {
- MainIndex: _components_MainIndex_vue__WEBPACK_IMPORTED_MODULE_2__.default
+ Navbar: _components_Header_Navbar_vue__WEBPACK_IMPORTED_MODULE_3__.default,
+ MainIndex: _components_MainIndex_vue__WEBPACK_IMPORTED_MODULE_2__.default,
+ Products: _components_Products_Products_vue__WEBPACK_IMPORTED_MODULE_4__.default
}
-}).use(_store_index__WEBPACK_IMPORTED_MODULE_1__.default).mount("#app"); //app.use(store);
+}).use(_store_index__WEBPACK_IMPORTED_MODULE_1__.default).use(router).mount("#app");
/***/ }),
@@ -16618,7 +16719,7 @@ __webpack_require__.r(__webpack_exports__);
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});
// Module
-___CSS_LOADER_EXPORT___.push([module.id, "\nheader[data-v-41f95097] {\n max-width: 1400px;\n}\n", ""]);
+___CSS_LOADER_EXPORT___.push([module.id, "\n.red[data-v-41f95097] {\n@apply text-8xl;\n}\n", ""]);
// Exports
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);
@@ -34461,6 +34562,32 @@ _MainIndex_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__.default.__fi
/***/ }),
+/***/ "./resources/js/components/Products/Products.vue":
+/*!*******************************************************!*\
+ !*** ./resources/js/components/Products/Products.vue ***!
+ \*******************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__
+/* harmony export */ });
+/* harmony import */ var _Products_vue_vue_type_template_id_4a553918__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Products.vue?vue&type=template&id=4a553918 */ "./resources/js/components/Products/Products.vue?vue&type=template&id=4a553918");
+/* harmony import */ var _Products_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Products.vue?vue&type=script&lang=js */ "./resources/js/components/Products/Products.vue?vue&type=script&lang=js");
+
+
+
+_Products_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__.default.render = _Products_vue_vue_type_template_id_4a553918__WEBPACK_IMPORTED_MODULE_0__.render
+/* hot reload */
+if (false) {}
+
+_Products_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__.default.__file = "resources/js/components/Products/Products.vue"
+
+/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_Products_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__.default);
+
+/***/ }),
+
/***/ "./resources/js/components/Header/Navbar.vue?vue&type=script&lang=js":
/*!***************************************************************************!*\
!*** ./resources/js/components/Header/Navbar.vue?vue&type=script&lang=js ***!
@@ -34491,6 +34618,22 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_5_use_0_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_MainIndex_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./MainIndex.vue?vue&type=script&lang=js */ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/MainIndex.vue?vue&type=script&lang=js");
+/***/ }),
+
+/***/ "./resources/js/components/Products/Products.vue?vue&type=script&lang=js":
+/*!*******************************************************************************!*\
+ !*** ./resources/js/components/Products/Products.vue?vue&type=script&lang=js ***!
+ \*******************************************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "default": () => /* reexport safe */ _node_modules_babel_loader_lib_index_js_clonedRuleSet_5_use_0_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Products_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__.default
+/* harmony export */ });
+/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_5_use_0_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Products_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!../../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Products.vue?vue&type=script&lang=js */ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Products/Products.vue?vue&type=script&lang=js");
+
+
/***/ }),
/***/ "./resources/js/components/Header/Navbar.vue?vue&type=template&id=41f95097&scoped=true":
@@ -34539,6 +34682,22 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_5_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_MainIndex_vue_vue_type_template_id_12fed784__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!../../../node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./MainIndex.vue?vue&type=template&id=12fed784 */ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/MainIndex.vue?vue&type=template&id=12fed784");
+/***/ }),
+
+/***/ "./resources/js/components/Products/Products.vue?vue&type=template&id=4a553918":
+/*!*************************************************************************************!*\
+ !*** ./resources/js/components/Products/Products.vue?vue&type=template&id=4a553918 ***!
+ \*************************************************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "render": () => /* reexport safe */ _node_modules_babel_loader_lib_index_js_clonedRuleSet_5_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Products_vue_vue_type_template_id_4a553918__WEBPACK_IMPORTED_MODULE_0__.render
+/* harmony export */ });
+/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_5_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Products_vue_vue_type_template_id_4a553918__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!../../../../node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!../../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Products.vue?vue&type=template&id=4a553918 */ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-5.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Products/Products.vue?vue&type=template&id=4a553918");
+
+
/***/ }),
/***/ "./resources/js/components/Header/Navbar.vue?vue&type=style&index=0&id=41f95097&scoped=true&lang=css":
@@ -34552,6 +34711,3319 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _node_modules_style_loader_dist_cjs_js_node_modules_css_loader_dist_cjs_js_clonedRuleSet_9_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_9_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Navbar_vue_vue_type_style_index_0_id_41f95097_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/style-loader/dist/cjs.js!../../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-9.use[1]!../../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-9.use[2]!../../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Navbar.vue?vue&type=style&index=0&id=41f95097&scoped=true&lang=css */ "./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-9.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-9.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./resources/js/components/Header/Navbar.vue?vue&type=style&index=0&id=41f95097&scoped=true&lang=css");
+/***/ }),
+
+/***/ "./node_modules/vue-router/dist/vue-router.esm-bundler.js":
+/*!****************************************************************!*\
+ !*** ./node_modules/vue-router/dist/vue-router.esm-bundler.js ***!
+ \****************************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "NavigationFailureType": () => /* binding */ NavigationFailureType,
+/* harmony export */ "RouterLink": () => /* binding */ RouterLink,
+/* harmony export */ "RouterView": () => /* binding */ RouterView,
+/* harmony export */ "START_LOCATION": () => /* binding */ START_LOCATION_NORMALIZED,
+/* harmony export */ "createMemoryHistory": () => /* binding */ createMemoryHistory,
+/* harmony export */ "createRouter": () => /* binding */ createRouter,
+/* harmony export */ "createRouterMatcher": () => /* binding */ createRouterMatcher,
+/* harmony export */ "createWebHashHistory": () => /* binding */ createWebHashHistory,
+/* harmony export */ "createWebHistory": () => /* binding */ createWebHistory,
+/* harmony export */ "isNavigationFailure": () => /* binding */ isNavigationFailure,
+/* harmony export */ "matchedRouteKey": () => /* binding */ matchedRouteKey,
+/* harmony export */ "onBeforeRouteLeave": () => /* binding */ onBeforeRouteLeave,
+/* harmony export */ "onBeforeRouteUpdate": () => /* binding */ onBeforeRouteUpdate,
+/* harmony export */ "parseQuery": () => /* binding */ parseQuery,
+/* harmony export */ "routeLocationKey": () => /* binding */ routeLocationKey,
+/* harmony export */ "routerKey": () => /* binding */ routerKey,
+/* harmony export */ "routerViewLocationKey": () => /* binding */ routerViewLocationKey,
+/* harmony export */ "stringifyQuery": () => /* binding */ stringifyQuery,
+/* harmony export */ "useLink": () => /* binding */ useLink,
+/* harmony export */ "useRoute": () => /* binding */ useRoute,
+/* harmony export */ "useRouter": () => /* binding */ useRouter,
+/* harmony export */ "viewDepthKey": () => /* binding */ viewDepthKey
+/* harmony export */ });
+/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.esm-bundler.js");
+/*!
+ * vue-router v4.0.3
+ * (c) 2021 Eduardo San Martin Morote
+ * @license MIT
+ */
+
+
+const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
+const PolySymbol = (name) =>
+// vr = vue router
+hasSymbol
+ ? Symbol(( true) ? '[vue-router]: ' + name : 0)
+ : (( true) ? '[vue-router]: ' : 0) + name;
+// rvlm = Router View Location Matched
+/**
+ * RouteRecord being rendered by the closest ancestor Router View. Used for
+ * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View
+ * Location Matched
+ *
+ * @internal
+ */
+const matchedRouteKey = /*#__PURE__*/ PolySymbol(( true) ? 'router view location matched' : 0);
+/**
+ * Allows overriding the router view depth to control which component in
+ * `matched` is rendered. rvd stands for Router View Depth
+ *
+ * @internal
+ */
+const viewDepthKey = /*#__PURE__*/ PolySymbol(( true) ? 'router view depth' : 0);
+/**
+ * Allows overriding the router instance returned by `useRouter` in tests. r
+ * stands for router
+ *
+ * @internal
+ */
+const routerKey = /*#__PURE__*/ PolySymbol(( true) ? 'router' : 0);
+/**
+ * Allows overriding the current route returned by `useRoute` in tests. rl
+ * stands for route location
+ *
+ * @internal
+ */
+const routeLocationKey = /*#__PURE__*/ PolySymbol(( true) ? 'route location' : 0);
+/**
+ * Allows overriding the current route used by router-view. Internally this is
+ * used when the `route` prop is passed.
+ *
+ * @internal
+ */
+const routerViewLocationKey = /*#__PURE__*/ PolySymbol(( true) ? 'router view location' : 0);
+
+const isBrowser = typeof window !== 'undefined';
+
+function isESModule(obj) {
+ return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module');
+}
+const assign = Object.assign;
+function applyToParams(fn, params) {
+ const newParams = {};
+ for (const key in params) {
+ const value = params[key];
+ newParams[key] = Array.isArray(value) ? value.map(fn) : fn(value);
+ }
+ return newParams;
+}
+let noop = () => { };
+
+function warn(msg) {
+ // avoid using ...args as it breaks in older Edge builds
+ const args = Array.from(arguments).slice(1);
+ console.warn.apply(console, ['[Vue Router warn]: ' + msg].concat(args));
+}
+
+const TRAILING_SLASH_RE = /\/$/;
+const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, '');
+/**
+ * Transforms an URI into a normalized history location
+ *
+ * @param parseQuery
+ * @param location - URI to normalize
+ * @param currentLocation - current absolute location. Allows resolving relative
+ * paths. Must start with `/`. Defaults to `/`
+ * @returns a normalized history location
+ */
+function parseURL(parseQuery, location, currentLocation = '/') {
+ let path, query = {}, searchString = '', hash = '';
+ // Could use URL and URLSearchParams but IE 11 doesn't support it
+ const searchPos = location.indexOf('?');
+ const hashPos = location.indexOf('#', searchPos > -1 ? searchPos : 0);
+ if (searchPos > -1) {
+ path = location.slice(0, searchPos);
+ searchString = location.slice(searchPos + 1, hashPos > -1 ? hashPos : location.length);
+ query = parseQuery(searchString);
+ }
+ if (hashPos > -1) {
+ path = path || location.slice(0, hashPos);
+ // keep the # character
+ hash = location.slice(hashPos, location.length);
+ }
+ // no search and no query
+ path = resolveRelativePath(path != null ? path : location, currentLocation);
+ // empty path means a relative query or hash `?foo=f`, `#thing`
+ return {
+ fullPath: path + (searchString && '?') + searchString + hash,
+ path,
+ query,
+ hash,
+ };
+}
+/**
+ * Stringifies a URL object
+ *
+ * @param stringifyQuery
+ * @param location
+ */
+function stringifyURL(stringifyQuery, location) {
+ let query = location.query ? stringifyQuery(location.query) : '';
+ return location.path + (query && '?') + query + (location.hash || '');
+}
+/**
+ * Strips off the base from the beginning of a location.pathname in a non
+ * case-sensitive way.
+ *
+ * @param pathname - location.pathname
+ * @param base - base to strip off
+ */
+function stripBase(pathname, base) {
+ // no base or base is not found at the beginning
+ if (!base || pathname.toLowerCase().indexOf(base.toLowerCase()))
+ return pathname;
+ return pathname.slice(base.length) || '/';
+}
+/**
+ * Checks if two RouteLocation are equal. This means that both locations are
+ * pointing towards the same {@link RouteRecord} and that all `params`, `query`
+ * parameters and `hash` are the same
+ *
+ * @param a - first {@link RouteLocation}
+ * @param b - second {@link RouteLocation}
+ */
+function isSameRouteLocation(stringifyQuery, a, b) {
+ let aLastIndex = a.matched.length - 1;
+ let bLastIndex = b.matched.length - 1;
+ return (aLastIndex > -1 &&
+ aLastIndex === bLastIndex &&
+ isSameRouteRecord(a.matched[aLastIndex], b.matched[bLastIndex]) &&
+ isSameRouteLocationParams(a.params, b.params) &&
+ stringifyQuery(a.query) === stringifyQuery(b.query) &&
+ a.hash === b.hash);
+}
+/**
+ * Check if two `RouteRecords` are equal. Takes into account aliases: they are
+ * considered equal to the `RouteRecord` they are aliasing.
+ *
+ * @param a - first {@link RouteRecord}
+ * @param b - second {@link RouteRecord}
+ */
+function isSameRouteRecord(a, b) {
+ // since the original record has an undefined value for aliasOf
+ // but all aliases point to the original record, this will always compare
+ // the original record
+ return (a.aliasOf || a) === (b.aliasOf || b);
+}
+function isSameRouteLocationParams(a, b) {
+ if (Object.keys(a).length !== Object.keys(b).length)
+ return false;
+ for (let key in a) {
+ if (!isSameRouteLocationParamsValue(a[key], b[key]))
+ return false;
+ }
+ return true;
+}
+function isSameRouteLocationParamsValue(a, b) {
+ return Array.isArray(a)
+ ? isEquivalentArray(a, b)
+ : Array.isArray(b)
+ ? isEquivalentArray(b, a)
+ : a === b;
+}
+/**
+ * Check if two arrays are the same or if an array with one single entry is the
+ * same as another primitive value. Used to check query and parameters
+ *
+ * @param a - array of values
+ * @param b - array of values or a single value
+ */
+function isEquivalentArray(a, b) {
+ return Array.isArray(b)
+ ? a.length === b.length && a.every((value, i) => value === b[i])
+ : a.length === 1 && a[0] === b;
+}
+/**
+ * Resolves a relative path that starts with `.`.
+ *
+ * @param to - path location we are resolving
+ * @param from - currentLocation.path, should start with `/`
+ */
+function resolveRelativePath(to, from) {
+ if (to.startsWith('/'))
+ return to;
+ if (( true) && !from.startsWith('/')) {
+ warn(`Cannot resolve a relative location without an absolute path. Trying to resolve "${to}" from "${from}". It should look like "/${from}".`);
+ return to;
+ }
+ if (!to)
+ return from;
+ const fromSegments = from.split('/');
+ const toSegments = to.split('/');
+ let position = fromSegments.length - 1;
+ let toPosition;
+ let segment;
+ for (toPosition = 0; toPosition < toSegments.length; toPosition++) {
+ segment = toSegments[toPosition];
+ // can't go below zero
+ if (position === 1 || segment === '.')
+ continue;
+ if (segment === '..')
+ position--;
+ // found something that is not relative path
+ else
+ break;
+ }
+ return (fromSegments.slice(0, position).join('/') +
+ '/' +
+ toSegments
+ .slice(toPosition - (toPosition === toSegments.length ? 1 : 0))
+ .join('/'));
+}
+
+var NavigationType;
+(function (NavigationType) {
+ NavigationType["pop"] = "pop";
+ NavigationType["push"] = "push";
+})(NavigationType || (NavigationType = {}));
+var NavigationDirection;
+(function (NavigationDirection) {
+ NavigationDirection["back"] = "back";
+ NavigationDirection["forward"] = "forward";
+ NavigationDirection["unknown"] = "";
+})(NavigationDirection || (NavigationDirection = {}));
+/**
+ * Starting location for Histories
+ */
+const START = '';
+// Generic utils
+/**
+ * Normalizes a base by removing any trailing slash and reading the base tag if
+ * present.
+ *
+ * @param base - base to normalize
+ */
+function normalizeBase(base) {
+ if (!base) {
+ if (isBrowser) {
+ // respect tag
+ const baseEl = document.querySelector('base');
+ base = (baseEl && baseEl.getAttribute('href')) || '/';
+ // strip full URL origin
+ base = base.replace(/^\w+:\/\/[^\/]+/, '');
+ }
+ else {
+ base = '/';
+ }
+ }
+ // ensure leading slash when it was removed by the regex above avoid leading
+ // slash with hash because the file could be read from the disk like file://
+ // and the leading slash would cause problems
+ if (base[0] !== '/' && base[0] !== '#')
+ base = '/' + base;
+ // remove the trailing slash so all other method can just do `base + fullPath`
+ // to build an href
+ return removeTrailingSlash(base);
+}
+// remove any character before the hash
+const BEFORE_HASH_RE = /^[^#]+#/;
+function createHref(base, location) {
+ return base.replace(BEFORE_HASH_RE, '#') + location;
+}
+
+function getElementPosition(el, offset) {
+ const docRect = document.documentElement.getBoundingClientRect();
+ const elRect = el.getBoundingClientRect();
+ return {
+ behavior: offset.behavior,
+ left: elRect.left - docRect.left - (offset.left || 0),
+ top: elRect.top - docRect.top - (offset.top || 0),
+ };
+}
+const computeScrollPosition = () => ({
+ left: window.pageXOffset,
+ top: window.pageYOffset,
+});
+function scrollToPosition(position) {
+ let scrollToOptions;
+ if ('el' in position) {
+ let positionEl = position.el;
+ const isIdSelector = typeof positionEl === 'string' && positionEl.startsWith('#');
+ /**
+ * `id`s can accept pretty much any characters, including CSS combinators
+ * like `>` or `~`. It's still possible to retrieve elements using
+ * `document.getElementById('~')` but it needs to be escaped when using
+ * `document.querySelector('#\\~')` for it to be valid. The only
+ * requirements for `id`s are them to be unique on the page and to not be
+ * empty (`id=""`). Because of that, when passing an id selector, it should
+ * be properly escaped for it to work with `querySelector`. We could check
+ * for the id selector to be simple (no CSS combinators `+ >~`) but that
+ * would make things inconsistent since they are valid characters for an
+ * `id` but would need to be escaped when using `querySelector`, breaking
+ * their usage and ending up in no selector returned. Selectors need to be
+ * escaped:
+ *
+ * - `#1-thing` becomes `#\31 -thing`
+ * - `#with~symbols` becomes `#with\\~symbols`
+ *
+ * - More information about the topic can be found at
+ * https://mathiasbynens.be/notes/html5-id-class.
+ * - Practical example: https://mathiasbynens.be/demo/html5-id
+ */
+ if (( true) && typeof position.el === 'string') {
+ if (!isIdSelector || !document.getElementById(position.el.slice(1))) {
+ try {
+ let foundEl = document.querySelector(position.el);
+ if (isIdSelector && foundEl) {
+ warn(`The selector "${position.el}" should be passed as "el: document.querySelector('${position.el}')" because it starts with "#".`);
+ // return to avoid other warnings
+ return;
+ }
+ }
+ catch (err) {
+ warn(`The selector "${position.el}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`);
+ // return to avoid other warnings
+ return;
+ }
+ }
+ }
+ const el = typeof positionEl === 'string'
+ ? isIdSelector
+ ? document.getElementById(positionEl.slice(1))
+ : document.querySelector(positionEl)
+ : positionEl;
+ if (!el) {
+ ( true) &&
+ warn(`Couldn't find element using selector "${position.el}" returned by scrollBehavior.`);
+ return;
+ }
+ scrollToOptions = getElementPosition(el, position);
+ }
+ else {
+ scrollToOptions = position;
+ }
+ if ('scrollBehavior' in document.documentElement.style)
+ window.scrollTo(scrollToOptions);
+ else {
+ window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.pageXOffset, scrollToOptions.top != null ? scrollToOptions.top : window.pageYOffset);
+ }
+}
+function getScrollKey(path, delta) {
+ const position = history.state ? history.state.position - delta : -1;
+ return position + path;
+}
+const scrollPositions = new Map();
+function saveScrollPosition(key, scrollPosition) {
+ scrollPositions.set(key, scrollPosition);
+}
+function getSavedScrollPosition(key) {
+ const scroll = scrollPositions.get(key);
+ // consume it so it's not used again
+ scrollPositions.delete(key);
+ return scroll;
+}
+// TODO: RFC about how to save scroll position
+/**
+ * ScrollBehavior instance used by the router to compute and restore the scroll
+ * position when navigating.
+ */
+// export interface ScrollHandler {
+// // returns a scroll position that can be saved in history
+// compute(): ScrollPositionEntry
+// // can take an extended ScrollPositionEntry
+// scroll(position: ScrollPosition): void
+// }
+// export const scrollHandler: ScrollHandler = {
+// compute: computeScroll,
+// scroll: scrollToPosition,
+// }
+
+let createBaseLocation = () => location.protocol + '//' + location.host;
+/**
+ * Creates a normalized history location from a window.location object
+ * @param location -
+ */
+function createCurrentLocation(base, location) {
+ const { pathname, search, hash } = location;
+ // allows hash based url
+ const hashPos = base.indexOf('#');
+ if (hashPos > -1) {
+ // prepend the starting slash to hash so the url starts with /#
+ let pathFromHash = hash.slice(1);
+ if (pathFromHash[0] !== '/')
+ pathFromHash = '/' + pathFromHash;
+ return stripBase(pathFromHash, '');
+ }
+ const path = stripBase(pathname, base);
+ return path + search + hash;
+}
+function useHistoryListeners(base, historyState, currentLocation, replace) {
+ let listeners = [];
+ let teardowns = [];
+ // TODO: should it be a stack? a Dict. Check if the popstate listener
+ // can trigger twice
+ let pauseState = null;
+ const popStateHandler = ({ state, }) => {
+ const to = createCurrentLocation(base, location);
+ const from = currentLocation.value;
+ const fromState = historyState.value;
+ let delta = 0;
+ if (state) {
+ currentLocation.value = to;
+ historyState.value = state;
+ // ignore the popstate and reset the pauseState
+ if (pauseState && pauseState === from) {
+ pauseState = null;
+ return;
+ }
+ delta = fromState ? state.position - fromState.position : 0;
+ }
+ else {
+ replace(to);
+ }
+ // console.log({ deltaFromCurrent })
+ // Here we could also revert the navigation by calling history.go(-delta)
+ // this listener will have to be adapted to not trigger again and to wait for the url
+ // to be updated before triggering the listeners. Some kind of validation function would also
+ // need to be passed to the listeners so the navigation can be accepted
+ // call all listeners
+ listeners.forEach(listener => {
+ listener(currentLocation.value, from, {
+ delta,
+ type: NavigationType.pop,
+ direction: delta
+ ? delta > 0
+ ? NavigationDirection.forward
+ : NavigationDirection.back
+ : NavigationDirection.unknown,
+ });
+ });
+ };
+ function pauseListeners() {
+ pauseState = currentLocation.value;
+ }
+ function listen(callback) {
+ // setup the listener and prepare teardown callbacks
+ listeners.push(callback);
+ const teardown = () => {
+ const index = listeners.indexOf(callback);
+ if (index > -1)
+ listeners.splice(index, 1);
+ };
+ teardowns.push(teardown);
+ return teardown;
+ }
+ function beforeUnloadListener() {
+ const { history } = window;
+ if (!history.state)
+ return;
+ history.replaceState(assign({}, history.state, { scroll: computeScrollPosition() }), '');
+ }
+ function destroy() {
+ for (const teardown of teardowns)
+ teardown();
+ teardowns = [];
+ window.removeEventListener('popstate', popStateHandler);
+ window.removeEventListener('beforeunload', beforeUnloadListener);
+ }
+ // setup the listeners and prepare teardown callbacks
+ window.addEventListener('popstate', popStateHandler);
+ window.addEventListener('beforeunload', beforeUnloadListener);
+ return {
+ pauseListeners,
+ listen,
+ destroy,
+ };
+}
+/**
+ * Creates a state object
+ */
+function buildState(back, current, forward, replaced = false, computeScroll = false) {
+ return {
+ back,
+ current,
+ forward,
+ replaced,
+ position: window.history.length,
+ scroll: computeScroll ? computeScrollPosition() : null,
+ };
+}
+function useHistoryStateNavigation(base) {
+ const { history, location } = window;
+ // private variables
+ let currentLocation = {
+ value: createCurrentLocation(base, location),
+ };
+ let historyState = { value: history.state };
+ // build current history entry as this is a fresh navigation
+ if (!historyState.value) {
+ changeLocation(currentLocation.value, {
+ back: null,
+ current: currentLocation.value,
+ forward: null,
+ // the length is off by one, we need to decrease it
+ position: history.length - 1,
+ replaced: true,
+ // don't add a scroll as the user may have an anchor and we want
+ // scrollBehavior to be triggered without a saved position
+ scroll: null,
+ }, true);
+ }
+ function changeLocation(to, state, replace) {
+ /**
+ * if a base tag is provided and we are on a normal domain, we have to
+ * respect the provided `base` attribute because pushState() will use it and
+ * potentially erase anything before the `#` like at
+ * https://github.com/vuejs/vue-router-next/issues/685 where a base of
+ * `/folder/#` but a base of `/` would erase the `/folder/` section. If
+ * there is no host, the `` tag makes no sense and if there isn't a
+ * base tag we can just use everything after the `#`.
+ */
+ const hashIndex = base.indexOf('#');
+ const url = hashIndex > -1
+ ? (location.host && document.querySelector('base')
+ ? base
+ : base.slice(hashIndex)) + to
+ : createBaseLocation() + base + to;
+ try {
+ // BROWSER QUIRK
+ // NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds
+ history[replace ? 'replaceState' : 'pushState'](state, '', url);
+ historyState.value = state;
+ }
+ catch (err) {
+ if ((true)) {
+ warn('Error with push/replace State', err);
+ }
+ else {}
+ // Force the navigation, this also resets the call count
+ location[replace ? 'replace' : 'assign'](url);
+ }
+ }
+ function replace(to, data) {
+ const state = assign({}, history.state, buildState(historyState.value.back,
+ // keep back and forward entries but override current position
+ to, historyState.value.forward, true), data, { position: historyState.value.position });
+ changeLocation(to, state, true);
+ currentLocation.value = to;
+ }
+ function push(to, data) {
+ // Add to current entry the information of where we are going
+ // as well as saving the current position
+ const currentState = assign({},
+ // use current history state to gracefully handle a wrong call to
+ // history.replaceState
+ // https://github.com/vuejs/vue-router-next/issues/366
+ historyState.value, history.state, {
+ forward: to,
+ scroll: computeScrollPosition(),
+ });
+ if (( true) && !history.state) {
+ warn(`history.state seems to have been manually replaced without preserving the necessary values. Make sure to preserve existing history state if you are manually calling history.replaceState:\n\n` +
+ `history.replaceState(history.state, '', url)\n\n` +
+ `You can find more information at https://next.router.vuejs.org/guide/migration/#usage-of-history-state.`);
+ }
+ changeLocation(currentState.current, currentState, true);
+ const state = assign({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data);
+ changeLocation(to, state, false);
+ currentLocation.value = to;
+ }
+ return {
+ location: currentLocation,
+ state: historyState,
+ push,
+ replace,
+ };
+}
+/**
+ * Creates an HTML5 history. Most common history for single page applications.
+ *
+ * @param base -
+ */
+function createWebHistory(base) {
+ base = normalizeBase(base);
+ const historyNavigation = useHistoryStateNavigation(base);
+ const historyListeners = useHistoryListeners(base, historyNavigation.state, historyNavigation.location, historyNavigation.replace);
+ function go(delta, triggerListeners = true) {
+ if (!triggerListeners)
+ historyListeners.pauseListeners();
+ history.go(delta);
+ }
+ const routerHistory = assign({
+ // it's overridden right after
+ location: '',
+ base,
+ go,
+ createHref: createHref.bind(null, base),
+ }, historyNavigation, historyListeners);
+ Object.defineProperty(routerHistory, 'location', {
+ get: () => historyNavigation.location.value,
+ });
+ Object.defineProperty(routerHistory, 'state', {
+ get: () => historyNavigation.state.value,
+ });
+ return routerHistory;
+}
+
+/**
+ * Creates a in-memory based history. The main purpose of this history is to handle SSR. It starts in a special location that is nowhere.
+ * It's up to the user to replace that location with the starter location by either calling `router.push` or `router.replace`.
+ *
+ * @param base - Base applied to all urls, defaults to '/'
+ * @returns a history object that can be passed to the router constructor
+ */
+function createMemoryHistory(base = '') {
+ let listeners = [];
+ let queue = [START];
+ let position = 0;
+ function setLocation(location) {
+ position++;
+ if (position === queue.length) {
+ // we are at the end, we can simply append a new entry
+ queue.push(location);
+ }
+ else {
+ // we are in the middle, we remove everything from here in the queue
+ queue.splice(position);
+ queue.push(location);
+ }
+ }
+ function triggerListeners(to, from, { direction, delta }) {
+ const info = {
+ direction,
+ delta,
+ type: NavigationType.pop,
+ };
+ for (let callback of listeners) {
+ callback(to, from, info);
+ }
+ }
+ const routerHistory = {
+ // rewritten by Object.defineProperty
+ location: START,
+ state: {},
+ base,
+ createHref: createHref.bind(null, base),
+ replace(to) {
+ // remove current entry and decrement position
+ queue.splice(position--, 1);
+ setLocation(to);
+ },
+ push(to, data) {
+ setLocation(to);
+ },
+ listen(callback) {
+ listeners.push(callback);
+ return () => {
+ const index = listeners.indexOf(callback);
+ if (index > -1)
+ listeners.splice(index, 1);
+ };
+ },
+ destroy() {
+ listeners = [];
+ },
+ go(delta, shouldTrigger = true) {
+ const from = this.location;
+ const direction =
+ // we are considering delta === 0 going forward, but in abstract mode
+ // using 0 for the delta doesn't make sense like it does in html5 where
+ // it reloads the page
+ delta < 0 ? NavigationDirection.back : NavigationDirection.forward;
+ position = Math.max(0, Math.min(position + delta, queue.length - 1));
+ if (shouldTrigger) {
+ triggerListeners(this.location, from, {
+ direction,
+ delta,
+ });
+ }
+ },
+ };
+ Object.defineProperty(routerHistory, 'location', {
+ get: () => queue[position],
+ });
+ return routerHistory;
+}
+
+/**
+ * Creates a hash history. Useful for web applications with no host (e.g.
+ * `file://`) or when configuring a server to handle any URL is not possible.
+ *
+ * @param base - optional base to provide. Defaults to `location.pathname +
+ * location.search` If there is a `` tag in the `head`, its value will be
+ * ignored in favor of this parameter **but note it affects all the
+ * history.pushState() calls**, meaning that if you use a `` tag, it's
+ * `href` value **has to match this parameter** (ignoring anything after the
+ * `#`).
+ *
+ * @example
+ * ```js
+ * // at https://example.com/folder
+ * createWebHashHistory() // gives a url of `https://example.com/folder#`
+ * createWebHashHistory('/folder/') // gives a url of `https://example.com/folder/#`
+ * // if the `#` is provided in the base, it won't be added by `createWebHashHistory`
+ * createWebHashHistory('/folder/#/app/') // gives a url of `https://example.com/folder/#/app/`
+ * // you should avoid doing this because it changes the original url and breaks copying urls
+ * createWebHashHistory('/other-folder/') // gives a url of `https://example.com/other-folder/#`
+ *
+ * // at file:///usr/etc/folder/index.html
+ * // for locations with no `host`, the base is ignored
+ * createWebHashHistory('/iAmIgnored') // gives a url of `file:///usr/etc/folder/index.html#`
+ * ```
+ */
+function createWebHashHistory(base) {
+ // Make sure this implementation is fine in terms of encoding, specially for IE11
+ // for `file://`, directly use the pathname and ignore the base
+ // location.pathname contains an initial `/` even at the root: `https://example.com`
+ base = location.host ? base || location.pathname + location.search : '';
+ // allow the user to provide a `#` in the middle: `/base/#/app`
+ if (base.indexOf('#') < 0)
+ base += '#';
+ if (( true) && !base.endsWith('#/') && !base.endsWith('#')) {
+ warn(`A hash base must end with a "#":\n"${base}" should be "${base.replace(/#.*$/, '#')}".`);
+ }
+ return createWebHistory(base);
+}
+
+function isRouteLocation(route) {
+ return typeof route === 'string' || (route && typeof route === 'object');
+}
+function isRouteName(name) {
+ return typeof name === 'string' || typeof name === 'symbol';
+}
+
+/**
+ * Initial route location where the router is. Can be used in navigation guards
+ * to differentiate the initial navigation.
+ *
+ * @example
+ * ```js
+ * import { START_LOCATION } from 'vue-router'
+ *
+ * router.beforeEach((to, from) => {
+ * if (from === START_LOCATION) {
+ * // initial navigation
+ * }
+ * })
+ * ```
+ */
+const START_LOCATION_NORMALIZED = {
+ path: '/',
+ name: undefined,
+ params: {},
+ query: {},
+ hash: '',
+ fullPath: '/',
+ matched: [],
+ meta: {},
+ redirectedFrom: undefined,
+};
+
+const NavigationFailureSymbol = /*#__PURE__*/ PolySymbol(( true) ? 'navigation failure' : 0);
+/**
+ * Enumeration with all possible types for navigation failures. Can be passed to
+ * {@link isNavigationFailure} to check for specific failures.
+ */
+var NavigationFailureType;
+(function (NavigationFailureType) {
+ /**
+ * An aborted navigation is a navigation that failed because a navigation
+ * guard returned `false` or called `next(false)`
+ */
+ NavigationFailureType[NavigationFailureType["aborted"] = 4] = "aborted";
+ /**
+ * A cancelled navigation is a navigation that failed because a more recent
+ * navigation finished started (not necessarily finished).
+ */
+ NavigationFailureType[NavigationFailureType["cancelled"] = 8] = "cancelled";
+ /**
+ * A duplicated navigation is a navigation that failed because it was
+ * initiated while already being at the exact same location.
+ */
+ NavigationFailureType[NavigationFailureType["duplicated"] = 16] = "duplicated";
+})(NavigationFailureType || (NavigationFailureType = {}));
+// DEV only debug messages
+const ErrorTypeMessages = {
+ [1 /* MATCHER_NOT_FOUND */]({ location, currentLocation }) {
+ return `No match for\n ${JSON.stringify(location)}${currentLocation
+ ? '\nwhile being at\n' + JSON.stringify(currentLocation)
+ : ''}`;
+ },
+ [2 /* NAVIGATION_GUARD_REDIRECT */]({ from, to, }) {
+ return `Redirected from "${from.fullPath}" to "${stringifyRoute(to)}" via a navigation guard.`;
+ },
+ [4 /* NAVIGATION_ABORTED */]({ from, to }) {
+ return `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard.`;
+ },
+ [8 /* NAVIGATION_CANCELLED */]({ from, to }) {
+ return `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new navigation.`;
+ },
+ [16 /* NAVIGATION_DUPLICATED */]({ from, to }) {
+ return `Avoided redundant navigation to current location: "${from.fullPath}".`;
+ },
+};
+function createRouterError(type, params) {
+ if (true) {
+ return assign(new Error(ErrorTypeMessages[type](params)), {
+ type,
+ [NavigationFailureSymbol]: true,
+ }, params);
+ }
+ else {}
+}
+function isNavigationFailure(error, type) {
+ return (error instanceof Error &&
+ NavigationFailureSymbol in error &&
+ (type == null || !!(error.type & type)));
+}
+const propertiesToLog = ['params', 'query', 'hash'];
+function stringifyRoute(to) {
+ if (typeof to === 'string')
+ return to;
+ if ('path' in to)
+ return to.path;
+ const location = {};
+ for (const key of propertiesToLog) {
+ if (key in to)
+ location[key] = to[key];
+ }
+ return JSON.stringify(location, null, 2);
+}
+
+// default pattern for a param: non greedy everything but /
+const BASE_PARAM_PATTERN = '[^/]+?';
+const BASE_PATH_PARSER_OPTIONS = {
+ sensitive: false,
+ strict: false,
+ start: true,
+ end: true,
+};
+// Special Regex characters that must be escaped in static tokens
+const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g;
+/**
+ * Creates a path parser from an array of Segments (a segment is an array of Tokens)
+ *
+ * @param segments - array of segments returned by tokenizePath
+ * @param extraOptions - optional options for the regexp
+ * @returns a PathParser
+ */
+function tokensToParser(segments, extraOptions) {
+ const options = assign({}, BASE_PATH_PARSER_OPTIONS, extraOptions);
+ // the amount of scores is the same as the length of segments except for the root segment "/"
+ let score = [];
+ // the regexp as a string
+ let pattern = options.start ? '^' : '';
+ // extracted keys
+ const keys = [];
+ for (const segment of segments) {
+ // the root segment needs special treatment
+ const segmentScores = segment.length ? [] : [90 /* Root */];
+ // allow trailing slash
+ if (options.strict && !segment.length)
+ pattern += '/';
+ for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) {
+ const token = segment[tokenIndex];
+ // resets the score if we are inside a sub segment /:a-other-:b
+ let subSegmentScore = 40 /* Segment */ +
+ (options.sensitive ? 0.25 /* BonusCaseSensitive */ : 0);
+ if (token.type === 0 /* Static */) {
+ // prepend the slash if we are starting a new segment
+ if (!tokenIndex)
+ pattern += '/';
+ pattern += token.value.replace(REGEX_CHARS_RE, '\\$&');
+ subSegmentScore += 40 /* Static */;
+ }
+ else if (token.type === 1 /* Param */) {
+ const { value, repeatable, optional, regexp } = token;
+ keys.push({
+ name: value,
+ repeatable,
+ optional,
+ });
+ const re = regexp ? regexp : BASE_PARAM_PATTERN;
+ // the user provided a custom regexp /:id(\\d+)
+ if (re !== BASE_PARAM_PATTERN) {
+ subSegmentScore += 10 /* BonusCustomRegExp */;
+ // make sure the regexp is valid before using it
+ try {
+ new RegExp(`(${re})`);
+ }
+ catch (err) {
+ throw new Error(`Invalid custom RegExp for param "${value}" (${re}): ` +
+ err.message);
+ }
+ }
+ // when we repeat we must take care of the repeating leading slash
+ let subPattern = repeatable ? `((?:${re})(?:/(?:${re}))*)` : `(${re})`;
+ // prepend the slash if we are starting a new segment
+ if (!tokenIndex)
+ subPattern = optional ? `(?:/${subPattern})` : '/' + subPattern;
+ if (optional)
+ subPattern += '?';
+ pattern += subPattern;
+ subSegmentScore += 20 /* Dynamic */;
+ if (optional)
+ subSegmentScore += -8 /* BonusOptional */;
+ if (repeatable)
+ subSegmentScore += -20 /* BonusRepeatable */;
+ if (re === '.*')
+ subSegmentScore += -50 /* BonusWildcard */;
+ }
+ segmentScores.push(subSegmentScore);
+ }
+ // an empty array like /home/ -> [[{home}], []]
+ // if (!segment.length) pattern += '/'
+ score.push(segmentScores);
+ }
+ // only apply the strict bonus to the last score
+ if (options.strict && options.end) {
+ const i = score.length - 1;
+ score[i][score[i].length - 1] += 0.7000000000000001 /* BonusStrict */;
+ }
+ // TODO: dev only warn double trailing slash
+ if (!options.strict)
+ pattern += '/?';
+ if (options.end)
+ pattern += '$';
+ // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else
+ else if (options.strict)
+ pattern += '(?:/|$)';
+ const re = new RegExp(pattern, options.sensitive ? '' : 'i');
+ function parse(path) {
+ const match = path.match(re);
+ const params = {};
+ if (!match)
+ return null;
+ for (let i = 1; i < match.length; i++) {
+ const value = match[i] || '';
+ const key = keys[i - 1];
+ params[key.name] = value && key.repeatable ? value.split('/') : value;
+ }
+ return params;
+ }
+ function stringify(params) {
+ let path = '';
+ // for optional parameters to allow to be empty
+ let avoidDuplicatedSlash = false;
+ for (const segment of segments) {
+ if (!avoidDuplicatedSlash || !path.endsWith('/'))
+ path += '/';
+ avoidDuplicatedSlash = false;
+ for (const token of segment) {
+ if (token.type === 0 /* Static */) {
+ path += token.value;
+ }
+ else if (token.type === 1 /* Param */) {
+ const { value, repeatable, optional } = token;
+ const param = value in params ? params[value] : '';
+ if (Array.isArray(param) && !repeatable)
+ throw new Error(`Provided param "${value}" is an array but it is not repeatable (* or + modifiers)`);
+ const text = Array.isArray(param) ? param.join('/') : param;
+ if (!text) {
+ if (optional) {
+ // remove the last slash as we could be at the end
+ if (path.endsWith('/'))
+ path = path.slice(0, -1);
+ // do not append a slash on the next iteration
+ else
+ avoidDuplicatedSlash = true;
+ }
+ else
+ throw new Error(`Missing required param "${value}"`);
+ }
+ path += text;
+ }
+ }
+ }
+ return path;
+ }
+ return {
+ re,
+ score,
+ keys,
+ parse,
+ stringify,
+ };
+}
+/**
+ * Compares an array of numbers as used in PathParser.score and returns a
+ * number. This function can be used to `sort` an array
+ * @param a - first array of numbers
+ * @param b - second array of numbers
+ * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b
+ * should be sorted first
+ */
+function compareScoreArray(a, b) {
+ let i = 0;
+ while (i < a.length && i < b.length) {
+ const diff = b[i] - a[i];
+ // only keep going if diff === 0
+ if (diff)
+ return diff;
+ i++;
+ }
+ // if the last subsegment was Static, the shorter segments should be sorted first
+ // otherwise sort the longest segment first
+ if (a.length < b.length) {
+ return a.length === 1 && a[0] === 40 /* Static */ + 40 /* Segment */
+ ? -1
+ : 1;
+ }
+ else if (a.length > b.length) {
+ return b.length === 1 && b[0] === 40 /* Static */ + 40 /* Segment */
+ ? 1
+ : -1;
+ }
+ return 0;
+}
+/**
+ * Compare function that can be used with `sort` to sort an array of PathParser
+ * @param a - first PathParser
+ * @param b - second PathParser
+ * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b
+ */
+function comparePathParserScore(a, b) {
+ let i = 0;
+ const aScore = a.score;
+ const bScore = b.score;
+ while (i < aScore.length && i < bScore.length) {
+ const comp = compareScoreArray(aScore[i], bScore[i]);
+ // do not return if both are equal
+ if (comp)
+ return comp;
+ i++;
+ }
+ // if a and b share the same score entries but b has more, sort b first
+ return bScore.length - aScore.length;
+ // this is the ternary version
+ // return aScore.length < bScore.length
+ // ? 1
+ // : aScore.length > bScore.length
+ // ? -1
+ // : 0
+}
+
+const ROOT_TOKEN = {
+ type: 0 /* Static */,
+ value: '',
+};
+const VALID_PARAM_RE = /[a-zA-Z0-9_]/;
+// After some profiling, the cache seems to be unnecessary because tokenizePath
+// (the slowest part of adding a route) is very fast
+// const tokenCache = new Map()
+function tokenizePath(path) {
+ if (!path)
+ return [[]];
+ if (path === '/')
+ return [[ROOT_TOKEN]];
+ if (!path.startsWith('/')) {
+ throw new Error(( true)
+ ? `Route paths should start with a "/": "${path}" should be "/${path}".`
+ : 0);
+ }
+ // if (tokenCache.has(path)) return tokenCache.get(path)!
+ function crash(message) {
+ throw new Error(`ERR (${state})/"${buffer}": ${message}`);
+ }
+ let state = 0 /* Static */;
+ let previousState = state;
+ const tokens = [];
+ // the segment will always be valid because we get into the initial state
+ // with the leading /
+ let segment;
+ function finalizeSegment() {
+ if (segment)
+ tokens.push(segment);
+ segment = [];
+ }
+ // index on the path
+ let i = 0;
+ // char at index
+ let char;
+ // buffer of the value read
+ let buffer = '';
+ // custom regexp for a param
+ let customRe = '';
+ function consumeBuffer() {
+ if (!buffer)
+ return;
+ if (state === 0 /* Static */) {
+ segment.push({
+ type: 0 /* Static */,
+ value: buffer,
+ });
+ }
+ else if (state === 1 /* Param */ ||
+ state === 2 /* ParamRegExp */ ||
+ state === 3 /* ParamRegExpEnd */) {
+ if (segment.length > 1 && (char === '*' || char === '+'))
+ crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`);
+ segment.push({
+ type: 1 /* Param */,
+ value: buffer,
+ regexp: customRe,
+ repeatable: char === '*' || char === '+',
+ optional: char === '*' || char === '?',
+ });
+ }
+ else {
+ crash('Invalid state to consume buffer');
+ }
+ buffer = '';
+ }
+ function addCharToBuffer() {
+ buffer += char;
+ }
+ while (i < path.length) {
+ char = path[i++];
+ if (char === '\\' && state !== 2 /* ParamRegExp */) {
+ previousState = state;
+ state = 4 /* EscapeNext */;
+ continue;
+ }
+ switch (state) {
+ case 0 /* Static */:
+ if (char === '/') {
+ if (buffer) {
+ consumeBuffer();
+ }
+ finalizeSegment();
+ }
+ else if (char === ':') {
+ consumeBuffer();
+ state = 1 /* Param */;
+ }
+ else {
+ addCharToBuffer();
+ }
+ break;
+ case 4 /* EscapeNext */:
+ addCharToBuffer();
+ state = previousState;
+ break;
+ case 1 /* Param */:
+ if (char === '(') {
+ state = 2 /* ParamRegExp */;
+ }
+ else if (VALID_PARAM_RE.test(char)) {
+ addCharToBuffer();
+ }
+ else {
+ consumeBuffer();
+ state = 0 /* Static */;
+ // go back one character if we were not modifying
+ if (char !== '*' && char !== '?' && char !== '+')
+ i--;
+ }
+ break;
+ case 2 /* ParamRegExp */:
+ // TODO: is it worth handling nested regexp? like :p(?:prefix_([^/]+)_suffix)
+ // it already works by escaping the closing )
+ // https://paths.esm.dev/?p=AAMeJbiAwQEcDKbAoAAkP60PG2R6QAvgNaA6AFACM2ABuQBB#
+ // is this really something people need since you can also write
+ // /prefix_:p()_suffix
+ if (char === ')') {
+ // handle the escaped )
+ if (customRe[customRe.length - 1] == '\\')
+ customRe = customRe.slice(0, -1) + char;
+ else
+ state = 3 /* ParamRegExpEnd */;
+ }
+ else {
+ customRe += char;
+ }
+ break;
+ case 3 /* ParamRegExpEnd */:
+ // same as finalizing a param
+ consumeBuffer();
+ state = 0 /* Static */;
+ // go back one character if we were not modifying
+ if (char !== '*' && char !== '?' && char !== '+')
+ i--;
+ customRe = '';
+ break;
+ default:
+ crash('Unknown state');
+ break;
+ }
+ }
+ if (state === 2 /* ParamRegExp */)
+ crash(`Unfinished custom RegExp for param "${buffer}"`);
+ consumeBuffer();
+ finalizeSegment();
+ // tokenCache.set(path, tokens)
+ return tokens;
+}
+
+function createRouteRecordMatcher(record, parent, options) {
+ const parser = tokensToParser(tokenizePath(record.path), options);
+ // warn against params with the same name
+ if ((true)) {
+ const existingKeys = new Set();
+ for (const key of parser.keys) {
+ if (existingKeys.has(key.name))
+ warn(`Found duplicated params with name "${key.name}" for path "${record.path}". Only the last one will be available on "$route.params".`);
+ existingKeys.add(key.name);
+ }
+ }
+ const matcher = assign(parser, {
+ record,
+ parent,
+ // these needs to be populated by the parent
+ children: [],
+ alias: [],
+ });
+ if (parent) {
+ // both are aliases or both are not aliases
+ // we don't want to mix them because the order is used when
+ // passing originalRecord in Matcher.addRoute
+ if (!matcher.record.aliasOf === !parent.record.aliasOf)
+ parent.children.push(matcher);
+ }
+ return matcher;
+}
+
+/**
+ * Creates a Router Matcher.
+ *
+ * @internal
+ * @param routes - array of initial routes
+ * @param globalOptions - global route options
+ */
+function createRouterMatcher(routes, globalOptions) {
+ // normalized ordered array of matchers
+ const matchers = [];
+ const matcherMap = new Map();
+ globalOptions = mergeOptions({ strict: false, end: true, sensitive: false }, globalOptions);
+ function getRecordMatcher(name) {
+ return matcherMap.get(name);
+ }
+ function addRoute(record, parent, originalRecord) {
+ // used later on to remove by name
+ let isRootAdd = !originalRecord;
+ let mainNormalizedRecord = normalizeRouteRecord(record);
+ // we might be the child of an alias
+ mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record;
+ const options = mergeOptions(globalOptions, record);
+ // generate an array of records to correctly handle aliases
+ const normalizedRecords = [
+ mainNormalizedRecord,
+ ];
+ if ('alias' in record) {
+ const aliases = typeof record.alias === 'string' ? [record.alias] : record.alias;
+ for (const alias of aliases) {
+ normalizedRecords.push(assign({}, mainNormalizedRecord, {
+ // this allows us to hold a copy of the `components` option
+ // so that async components cache is hold on the original record
+ components: originalRecord
+ ? originalRecord.record.components
+ : mainNormalizedRecord.components,
+ path: alias,
+ // we might be the child of an alias
+ aliasOf: originalRecord
+ ? originalRecord.record
+ : mainNormalizedRecord,
+ }));
+ }
+ }
+ let matcher;
+ let originalMatcher;
+ for (const normalizedRecord of normalizedRecords) {
+ let { path } = normalizedRecord;
+ // Build up the path for nested routes if the child isn't an absolute
+ // route. Only add the / delimiter if the child path isn't empty and if the
+ // parent path doesn't have a trailing slash
+ if (parent && path[0] !== '/') {
+ let parentPath = parent.record.path;
+ let connectingSlash = parentPath[parentPath.length - 1] === '/' ? '' : '/';
+ normalizedRecord.path =
+ parent.record.path + (path && connectingSlash + path);
+ }
+ if (( true) && normalizedRecord.path === '*') {
+ throw new Error('Catch all routes ("*") must now be defined using a param with a custom regexp.\n' +
+ 'See more at https://next.router.vuejs.org/guide/migration/#removed-star-or-catch-all-routes.');
+ }
+ // create the object before hand so it can be passed to children
+ matcher = createRouteRecordMatcher(normalizedRecord, parent, options);
+ if (( true) && parent && path[0] === '/')
+ checkMissingParamsInAbsolutePath(matcher, parent);
+ // if we are an alias we must tell the original record that we exist
+ // so we can be removed
+ if (originalRecord) {
+ originalRecord.alias.push(matcher);
+ if ((true)) {
+ checkSameParams(originalRecord, matcher);
+ }
+ }
+ else {
+ // otherwise, the first record is the original and others are aliases
+ originalMatcher = originalMatcher || matcher;
+ if (originalMatcher !== matcher)
+ originalMatcher.alias.push(matcher);
+ // remove the route if named and only for the top record (avoid in nested calls)
+ // this works because the original record is the first one
+ if (isRootAdd && record.name && !isAliasRecord(matcher))
+ removeRoute(record.name);
+ }
+ if ('children' in mainNormalizedRecord) {
+ let children = mainNormalizedRecord.children;
+ for (let i = 0; i < children.length; i++) {
+ addRoute(children[i], matcher, originalRecord && originalRecord.children[i]);
+ }
+ }
+ // if there was no original record, then the first one was not an alias and all
+ // other alias (if any) need to reference this record when adding children
+ originalRecord = originalRecord || matcher;
+ // TODO: add normalized records for more flexibility
+ // if (parent && isAliasRecord(originalRecord)) {
+ // parent.children.push(originalRecord)
+ // }
+ insertMatcher(matcher);
+ }
+ return originalMatcher
+ ? () => {
+ // since other matchers are aliases, they should be removed by the original matcher
+ removeRoute(originalMatcher);
+ }
+ : noop;
+ }
+ function removeRoute(matcherRef) {
+ if (isRouteName(matcherRef)) {
+ const matcher = matcherMap.get(matcherRef);
+ if (matcher) {
+ matcherMap.delete(matcherRef);
+ matchers.splice(matchers.indexOf(matcher), 1);
+ matcher.children.forEach(removeRoute);
+ matcher.alias.forEach(removeRoute);
+ }
+ }
+ else {
+ let index = matchers.indexOf(matcherRef);
+ if (index > -1) {
+ matchers.splice(index, 1);
+ if (matcherRef.record.name)
+ matcherMap.delete(matcherRef.record.name);
+ matcherRef.children.forEach(removeRoute);
+ matcherRef.alias.forEach(removeRoute);
+ }
+ }
+ }
+ function getRoutes() {
+ return matchers;
+ }
+ function insertMatcher(matcher) {
+ let i = 0;
+ // console.log('i is', { i })
+ while (i < matchers.length &&
+ comparePathParserScore(matcher, matchers[i]) >= 0)
+ i++;
+ // console.log('END i is', { i })
+ // while (i < matchers.length && matcher.score <= matchers[i].score) i++
+ matchers.splice(i, 0, matcher);
+ // only add the original record to the name map
+ if (matcher.record.name && !isAliasRecord(matcher))
+ matcherMap.set(matcher.record.name, matcher);
+ }
+ function resolve(location, currentLocation) {
+ let matcher;
+ let params = {};
+ let path;
+ let name;
+ if ('name' in location && location.name) {
+ matcher = matcherMap.get(location.name);
+ if (!matcher)
+ throw createRouterError(1 /* MATCHER_NOT_FOUND */, {
+ location,
+ });
+ name = matcher.record.name;
+ params = assign(
+ // paramsFromLocation is a new object
+ paramsFromLocation(currentLocation.params,
+ // only keep params that exist in the resolved location
+ // TODO: only keep optional params coming from a parent record
+ matcher.keys.filter(k => !k.optional).map(k => k.name)), location.params);
+ // throws if cannot be stringified
+ path = matcher.stringify(params);
+ }
+ else if ('path' in location) {
+ // no need to resolve the path with the matcher as it was provided
+ // this also allows the user to control the encoding
+ path = location.path;
+ if (( true) && !path.startsWith('/')) {
+ warn(`The Matcher cannot resolve relative paths but received "${path}". Unless you directly called \`matcher.resolve("${path}")\`, this is probably a bug in vue-router. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-router-next.`);
+ }
+ matcher = matchers.find(m => m.re.test(path));
+ // matcher should have a value after the loop
+ if (matcher) {
+ // TODO: dev warning of unused params if provided
+ // we know the matcher works because we tested the regexp
+ params = matcher.parse(path);
+ name = matcher.record.name;
+ }
+ // location is a relative path
+ }
+ else {
+ // match by name or path of current route
+ matcher = currentLocation.name
+ ? matcherMap.get(currentLocation.name)
+ : matchers.find(m => m.re.test(currentLocation.path));
+ if (!matcher)
+ throw createRouterError(1 /* MATCHER_NOT_FOUND */, {
+ location,
+ currentLocation,
+ });
+ name = matcher.record.name;
+ // since we are navigating to the same location, we don't need to pick the
+ // params like when `name` is provided
+ params = assign({}, currentLocation.params, location.params);
+ path = matcher.stringify(params);
+ }
+ const matched = [];
+ let parentMatcher = matcher;
+ while (parentMatcher) {
+ // reversed order so parents are at the beginning
+ matched.unshift(parentMatcher.record);
+ parentMatcher = parentMatcher.parent;
+ }
+ return {
+ name,
+ path,
+ params,
+ matched,
+ meta: mergeMetaFields(matched),
+ };
+ }
+ // add initial routes
+ routes.forEach(route => addRoute(route));
+ return { addRoute, resolve, removeRoute, getRoutes, getRecordMatcher };
+}
+function paramsFromLocation(params, keys) {
+ let newParams = {};
+ for (let key of keys) {
+ if (key in params)
+ newParams[key] = params[key];
+ }
+ return newParams;
+}
+/**
+ * Normalizes a RouteRecordRaw. Creates a copy
+ *
+ * @param record
+ * @returns the normalized version
+ */
+function normalizeRouteRecord(record) {
+ return {
+ path: record.path,
+ redirect: record.redirect,
+ name: record.name,
+ meta: record.meta || {},
+ aliasOf: undefined,
+ beforeEnter: record.beforeEnter,
+ props: normalizeRecordProps(record),
+ children: record.children || [],
+ instances: {},
+ leaveGuards: new Set(),
+ updateGuards: new Set(),
+ enterCallbacks: {},
+ components: 'components' in record
+ ? record.components || {}
+ : { default: record.component },
+ };
+}
+/**
+ * Normalize the optional `props` in a record to always be an object similar to
+ * components. Also accept a boolean for components.
+ * @param record
+ */
+function normalizeRecordProps(record) {
+ const propsObject = {};
+ // props does not exist on redirect records but we can set false directly
+ const props = record.props || false;
+ if ('component' in record) {
+ propsObject.default = props;
+ }
+ else {
+ // NOTE: we could also allow a function to be applied to every component.
+ // Would need user feedback for use cases
+ for (let name in record.components)
+ propsObject[name] = typeof props === 'boolean' ? props : props[name];
+ }
+ return propsObject;
+}
+/**
+ * Checks if a record or any of its parent is an alias
+ * @param record
+ */
+function isAliasRecord(record) {
+ while (record) {
+ if (record.record.aliasOf)
+ return true;
+ record = record.parent;
+ }
+ return false;
+}
+/**
+ * Merge meta fields of an array of records
+ *
+ * @param matched - array of matched records
+ */
+function mergeMetaFields(matched) {
+ return matched.reduce((meta, record) => assign(meta, record.meta), {});
+}
+function mergeOptions(defaults, partialOptions) {
+ let options = {};
+ for (let key in defaults) {
+ options[key] =
+ key in partialOptions ? partialOptions[key] : defaults[key];
+ }
+ return options;
+}
+function isSameParam(a, b) {
+ return (a.name === b.name &&
+ a.optional === b.optional &&
+ a.repeatable === b.repeatable);
+}
+function checkSameParams(a, b) {
+ for (let key of a.keys) {
+ if (!b.keys.find(isSameParam.bind(null, key)))
+ return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" should have the exact same param named "${key.name}"`);
+ }
+ for (let key of b.keys) {
+ if (!a.keys.find(isSameParam.bind(null, key)))
+ return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" should have the exact same param named "${key.name}"`);
+ }
+}
+function checkMissingParamsInAbsolutePath(record, parent) {
+ for (let key of parent.keys) {
+ if (!record.keys.find(isSameParam.bind(null, key)))
+ return warn(`Absolute path "${record.record.path}" should have the exact same param named "${key.name}" as its parent "${parent.record.path}".`);
+ }
+}
+
+/**
+ * Encoding Rules ␣ = Space Path: ␣ " < > # ? { } Query: ␣ " < > # & = Hash: ␣ "
+ * < > `
+ *
+ * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2)
+ * defines some extra characters to be encoded. Most browsers do not encode them
+ * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to
+ * also encode `!'()*`. Leaving unencoded only ASCII alphanumeric(`a-zA-Z0-9`)
+ * plus `-._~`. This extra safety should be applied to query by patching the
+ * string returned by encodeURIComponent encodeURI also encodes `[\]^`. `\`
+ * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\`
+ * into a `/` if directly typed in. The _backtick_ (`````) should also be
+ * encoded everywhere because some browsers like FF encode it when directly
+ * written while others don't. Safari and IE don't encode ``"<>{}``` in hash.
+ */
+// const EXTRA_RESERVED_RE = /[!'()*]/g
+// const encodeReservedReplacer = (c: string) => '%' + c.charCodeAt(0).toString(16)
+const HASH_RE = /#/g; // %23
+const AMPERSAND_RE = /&/g; // %26
+const SLASH_RE = /\//g; // %2F
+const EQUAL_RE = /=/g; // %3D
+const IM_RE = /\?/g; // %3F
+const PLUS_RE = /\+/g; // %2B
+/**
+ * NOTE: It's not clear to me if we should encode the + symbol in queries, it
+ * seems to be less flexible than not doing so and I can't find out the legacy
+ * systems requiring this for regular requests like text/html. In the standard,
+ * the encoding of the plus character is only mentioned for
+ * application/x-www-form-urlencoded
+ * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo
+ * leave the plus character as is in queries. To be more flexible, we allow the
+ * plus character on the query but it can also be manually encoded by the user.
+ *
+ * Resources:
+ * - https://url.spec.whatwg.org/#urlencoded-parsing
+ * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20
+ */
+const ENC_BRACKET_OPEN_RE = /%5B/g; // [
+const ENC_BRACKET_CLOSE_RE = /%5D/g; // ]
+const ENC_CARET_RE = /%5E/g; // ^
+const ENC_BACKTICK_RE = /%60/g; // `
+const ENC_CURLY_OPEN_RE = /%7B/g; // {
+const ENC_PIPE_RE = /%7C/g; // |
+const ENC_CURLY_CLOSE_RE = /%7D/g; // }
+const ENC_SPACE_RE = /%20/g; // }
+/**
+ * Encode characters that need to be encoded on the path, search and hash
+ * sections of the URL.
+ *
+ * @internal
+ * @param text - string to encode
+ * @returns encoded string
+ */
+function commonEncode(text) {
+ return encodeURI('' + text)
+ .replace(ENC_PIPE_RE, '|')
+ .replace(ENC_BRACKET_OPEN_RE, '[')
+ .replace(ENC_BRACKET_CLOSE_RE, ']');
+}
+/**
+ * Encode characters that need to be encoded on the hash section of the URL.
+ *
+ * @param text - string to encode
+ * @returns encoded string
+ */
+function encodeHash(text) {
+ return commonEncode(text)
+ .replace(ENC_CURLY_OPEN_RE, '{')
+ .replace(ENC_CURLY_CLOSE_RE, '}')
+ .replace(ENC_CARET_RE, '^');
+}
+/**
+ * Encode characters that need to be encoded query values on the query
+ * section of the URL.
+ *
+ * @param text - string to encode
+ * @returns encoded string
+ */
+function encodeQueryValue(text) {
+ return (commonEncode(text)
+ // Encode the space as +, encode the + to differentiate it from the space
+ .replace(PLUS_RE, '%2B')
+ .replace(ENC_SPACE_RE, '+')
+ .replace(HASH_RE, '%23')
+ .replace(AMPERSAND_RE, '%26')
+ .replace(ENC_BACKTICK_RE, '`')
+ .replace(ENC_CURLY_OPEN_RE, '{')
+ .replace(ENC_CURLY_CLOSE_RE, '}')
+ .replace(ENC_CARET_RE, '^'));
+}
+/**
+ * Like `encodeQueryValue` but also encodes the `=` character.
+ *
+ * @param text - string to encode
+ */
+function encodeQueryKey(text) {
+ return encodeQueryValue(text).replace(EQUAL_RE, '%3D');
+}
+/**
+ * Encode characters that need to be encoded on the path section of the URL.
+ *
+ * @param text - string to encode
+ * @returns encoded string
+ */
+function encodePath(text) {
+ return commonEncode(text).replace(HASH_RE, '%23').replace(IM_RE, '%3F');
+}
+/**
+ * Encode characters that need to be encoded on the path section of the URL as a
+ * param. This function encodes everything {@link encodePath} does plus the
+ * slash (`/`) character.
+ *
+ * @param text - string to encode
+ * @returns encoded string
+ */
+function encodeParam(text) {
+ return encodePath(text).replace(SLASH_RE, '%2F');
+}
+/**
+ * Decode text using `decodeURIComponent`. Returns the original text if it
+ * fails.
+ *
+ * @param text - string to decode
+ * @returns decoded string
+ */
+function decode(text) {
+ try {
+ return decodeURIComponent('' + text);
+ }
+ catch (err) {
+ ( true) && warn(`Error decoding "${text}". Using original value`);
+ }
+ return '' + text;
+}
+
+/**
+ * Transforms a queryString into a {@link LocationQuery} object. Accept both, a
+ * version with the leading `?` and without Should work as URLSearchParams
+
+ * @internal
+ *
+ * @param search - search string to parse
+ * @returns a query object
+ */
+function parseQuery(search) {
+ const query = {};
+ // avoid creating an object with an empty key and empty value
+ // because of split('&')
+ if (search === '' || search === '?')
+ return query;
+ const hasLeadingIM = search[0] === '?';
+ const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&');
+ for (let i = 0; i < searchParams.length; ++i) {
+ // pre decode the + into space
+ const searchParam = searchParams[i].replace(PLUS_RE, ' ');
+ // allow the = character
+ let eqPos = searchParam.indexOf('=');
+ let key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos));
+ let value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1));
+ if (key in query) {
+ // an extra variable for ts types
+ let currentValue = query[key];
+ if (!Array.isArray(currentValue)) {
+ currentValue = query[key] = [currentValue];
+ }
+ currentValue.push(value);
+ }
+ else {
+ query[key] = value;
+ }
+ }
+ return query;
+}
+/**
+ * Stringifies a {@link LocationQueryRaw} object. Like `URLSearchParams`, it
+ * doesn't prepend a `?`
+ *
+ * @internal
+ *
+ * @param query - query object to stringify
+ * @returns string version of the query without the leading `?`
+ */
+function stringifyQuery(query) {
+ let search = '';
+ for (let key in query) {
+ if (search.length)
+ search += '&';
+ const value = query[key];
+ key = encodeQueryKey(key);
+ if (value == null) {
+ // only null adds the value
+ if (value !== undefined)
+ search += key;
+ continue;
+ }
+ // keep null values
+ let values = Array.isArray(value)
+ ? value.map(v => v && encodeQueryValue(v))
+ : [value && encodeQueryValue(value)];
+ for (let i = 0; i < values.length; i++) {
+ // only append & with i > 0
+ search += (i ? '&' : '') + key;
+ if (values[i] != null)
+ search += ('=' + values[i]);
+ }
+ }
+ return search;
+}
+/**
+ * Transforms a {@link LocationQueryRaw} into a {@link LocationQuery} by casting
+ * numbers into strings, removing keys with an undefined value and replacing
+ * undefined with null in arrays
+ *
+ * @param query - query object to normalize
+ * @returns a normalized query object
+ */
+function normalizeQuery(query) {
+ const normalizedQuery = {};
+ for (let key in query) {
+ let value = query[key];
+ if (value !== undefined) {
+ normalizedQuery[key] = Array.isArray(value)
+ ? value.map(v => (v == null ? null : '' + v))
+ : value == null
+ ? value
+ : '' + value;
+ }
+ }
+ return normalizedQuery;
+}
+
+/**
+ * Create a list of callbacks that can be reset. Used to create before and after navigation guards list
+ */
+function useCallbacks() {
+ let handlers = [];
+ function add(handler) {
+ handlers.push(handler);
+ return () => {
+ const i = handlers.indexOf(handler);
+ if (i > -1)
+ handlers.splice(i, 1);
+ };
+ }
+ function reset() {
+ handlers = [];
+ }
+ return {
+ add,
+ list: () => handlers,
+ reset,
+ };
+}
+
+function registerGuard(record, name, guard) {
+ const removeFromList = () => {
+ record[name].delete(guard);
+ };
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.onUnmounted)(removeFromList);
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.onDeactivated)(removeFromList);
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.onActivated)(() => {
+ record[name].add(guard);
+ });
+ record[name].add(guard);
+}
+/**
+ * Add a navigation guard that triggers whenever the component for the current
+ * location is about to be left. Similar to {@link beforeRouteLeave} but can be
+ * used in any component. The guard is removed when the component is unmounted.
+ *
+ * @param leaveGuard - {@link NavigationGuard}
+ */
+function onBeforeRouteLeave(leaveGuard) {
+ if (( true) && !(0,vue__WEBPACK_IMPORTED_MODULE_0__.getCurrentInstance)()) {
+ warn('getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function');
+ return;
+ }
+ const activeRecord = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(matchedRouteKey, {}).value;
+ if (!activeRecord) {
+ ( true) &&
+ warn('No active route record was found. Are you missing a component?');
+ return;
+ }
+ registerGuard(activeRecord, 'leaveGuards', leaveGuard);
+}
+/**
+ * Add a navigation guard that triggers whenever the current location is about
+ * to be updated. Similar to {@link beforeRouteUpdate} but can be used in any
+ * component. The guard is removed when the component is unmounted.
+ *
+ * @param updateGuard - {@link NavigationGuard}
+ */
+function onBeforeRouteUpdate(updateGuard) {
+ if (( true) && !(0,vue__WEBPACK_IMPORTED_MODULE_0__.getCurrentInstance)()) {
+ warn('getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function');
+ return;
+ }
+ const activeRecord = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(matchedRouteKey, {}).value;
+ if (!activeRecord) {
+ ( true) &&
+ warn('No active route record was found. Are you missing a component?');
+ return;
+ }
+ registerGuard(activeRecord, 'updateGuards', updateGuard);
+}
+function guardToPromiseFn(guard, to, from, record, name) {
+ // keep a reference to the enterCallbackArray to prevent pushing callbacks if a new navigation took place
+ const enterCallbackArray = record &&
+ // name is defined if record is because of the function overload
+ (record.enterCallbacks[name] = record.enterCallbacks[name] || []);
+ return () => new Promise((resolve, reject) => {
+ const next = (valid) => {
+ if (valid === false)
+ reject(createRouterError(4 /* NAVIGATION_ABORTED */, {
+ from,
+ to,
+ }));
+ else if (valid instanceof Error) {
+ reject(valid);
+ }
+ else if (isRouteLocation(valid)) {
+ reject(createRouterError(2 /* NAVIGATION_GUARD_REDIRECT */, {
+ from: to,
+ to: valid,
+ }));
+ }
+ else {
+ if (enterCallbackArray &&
+ // since enterCallbackArray is truthy, both record and name also are
+ record.enterCallbacks[name] === enterCallbackArray &&
+ typeof valid === 'function')
+ enterCallbackArray.push(valid);
+ resolve();
+ }
+ };
+ // wrapping with Promise.resolve allows it to work with both async and sync guards
+ const guardReturn = guard.call(record && record.instances[name], to, from, ( true) ? canOnlyBeCalledOnce(next, to, from) : 0);
+ let guardCall = Promise.resolve(guardReturn);
+ if (guard.length < 3)
+ guardCall = guardCall.then(next);
+ if (( true) && guard.length > 2) {
+ const message = `The "next" callback was never called inside of ${guard.name ? '"' + guard.name + '"' : ''}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`;
+ if (typeof guardReturn === 'object' && 'then' in guardReturn) {
+ guardCall = guardCall.then(resolvedValue => {
+ // @ts-ignore: _called is added at canOnlyBeCalledOnce
+ if (!next._called) {
+ warn(message);
+ return Promise.reject(new Error('Invalid navigation guard'));
+ }
+ return resolvedValue;
+ });
+ // TODO: test me!
+ }
+ else if (guardReturn !== undefined) {
+ // @ts-ignore: _called is added at canOnlyBeCalledOnce
+ if (!next._called) {
+ warn(message);
+ reject(new Error('Invalid navigation guard'));
+ return;
+ }
+ }
+ }
+ guardCall.catch(err => reject(err));
+ });
+}
+function canOnlyBeCalledOnce(next, to, from) {
+ let called = 0;
+ return function () {
+ if (called++ === 1)
+ warn(`The "next" callback was called more than once in one navigation guard when going from "${from.fullPath}" to "${to.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`);
+ // @ts-ignore: we put it in the original one because it's easier to check
+ next._called = true;
+ if (called === 1)
+ next.apply(null, arguments);
+ };
+}
+function extractComponentsGuards(matched, guardType, to, from) {
+ const guards = [];
+ for (const record of matched) {
+ for (const name in record.components) {
+ let rawComponent = record.components[name];
+ if ((true)) {
+ if (!rawComponent ||
+ (typeof rawComponent !== 'object' &&
+ typeof rawComponent !== 'function')) {
+ warn(`Component "${name}" in record with path "${record.path}" is not` +
+ ` a valid component. Received "${String(rawComponent)}".`);
+ // throw to ensure we stop here but warn to ensure the message isn't
+ // missed by the user
+ throw new Error('Invalid route component');
+ }
+ else if ('then' in rawComponent) {
+ // warn if user wrote import('/component.vue') instead of () =>
+ // import('./component.vue')
+ warn(`Component "${name}" in record with path "${record.path}" is a ` +
+ `Promise instead of a function that returns a Promise. Did you ` +
+ `write "import('./MyPage.vue')" instead of ` +
+ `"() => import('./MyPage.vue')" ? This will break in ` +
+ `production if not fixed.`);
+ let promise = rawComponent;
+ rawComponent = () => promise;
+ }
+ else if (rawComponent.__asyncLoader &&
+ // warn only once per component
+ !rawComponent.__warnedDefineAsync) {
+ rawComponent.__warnedDefineAsync = true;
+ warn(`Component "${name}" in record with path "${record.path}" is defined ` +
+ `using "defineAsyncComponent()". ` +
+ `Write "() => import('./MyPage.vue')" instead of ` +
+ `"defineAsyncComponent(() => import('./MyPage.vue'))".`);
+ }
+ }
+ // skip update and leave guards if the route component is not mounted
+ if (guardType !== 'beforeRouteEnter' && !record.instances[name])
+ continue;
+ if (isRouteComponent(rawComponent)) {
+ // __vccOpts is added by vue-class-component and contain the regular options
+ let options = rawComponent.__vccOpts || rawComponent;
+ const guard = options[guardType];
+ guard && guards.push(guardToPromiseFn(guard, to, from, record, name));
+ }
+ else {
+ // start requesting the chunk already
+ let componentPromise = rawComponent();
+ if (( true) && !('catch' in componentPromise)) {
+ warn(`Component "${name}" in record with path "${record.path}" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.`);
+ componentPromise = Promise.resolve(componentPromise);
+ }
+ else {
+ // display the error if any
+ componentPromise = componentPromise.catch(( true) ? err => err && warn(err) : 0);
+ }
+ guards.push(() => componentPromise.then(resolved => {
+ if (!resolved)
+ return Promise.reject(new Error(`Couldn't resolve component "${name}" at "${record.path}"`));
+ const resolvedComponent = isESModule(resolved)
+ ? resolved.default
+ : resolved;
+ // replace the function with the resolved component
+ record.components[name] = resolvedComponent;
+ // @ts-ignore: the options types are not propagated to Component
+ const guard = resolvedComponent[guardType];
+ return guard && guardToPromiseFn(guard, to, from, record, name)();
+ }));
+ }
+ }
+ }
+ return guards;
+}
+/**
+ * Allows differentiating lazy components from functional components and vue-class-component
+ * @param component
+ */
+function isRouteComponent(component) {
+ return (typeof component === 'object' ||
+ 'displayName' in component ||
+ 'props' in component ||
+ '__vccOpts' in component);
+}
+
+// TODO: we could allow currentRoute as a prop to expose `isActive` and
+// `isExactActive` behavior should go through an RFC
+function useLink(props) {
+ const router = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(routerKey);
+ const currentRoute = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(routeLocationKey);
+ const route = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => router.resolve((0,vue__WEBPACK_IMPORTED_MODULE_0__.unref)(props.to)));
+ const activeRecordIndex = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => {
+ let { matched } = route.value;
+ let { length } = matched;
+ const routeMatched = matched[length - 1];
+ let currentMatched = currentRoute.matched;
+ if (!routeMatched || !currentMatched.length)
+ return -1;
+ let index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched));
+ if (index > -1)
+ return index;
+ // possible parent record
+ let parentRecordPath = getOriginalPath(matched[length - 2]);
+ return (
+ // we are dealing with nested routes
+ length > 1 &&
+ // if the parent and matched route have the same path, this link is
+ // referring to the empty child. Or we currently are on a different
+ // child of the same parent
+ getOriginalPath(routeMatched) === parentRecordPath &&
+ // avoid comparing the child with its parent
+ currentMatched[currentMatched.length - 1].path !== parentRecordPath
+ ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2]))
+ : index);
+ });
+ const isActive = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => activeRecordIndex.value > -1 &&
+ includesParams(currentRoute.params, route.value.params));
+ const isExactActive = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => activeRecordIndex.value > -1 &&
+ activeRecordIndex.value === currentRoute.matched.length - 1 &&
+ isSameRouteLocationParams(currentRoute.params, route.value.params));
+ function navigate(e = {}) {
+ if (guardEvent(e))
+ return router[(0,vue__WEBPACK_IMPORTED_MODULE_0__.unref)(props.replace) ? 'replace' : 'push']((0,vue__WEBPACK_IMPORTED_MODULE_0__.unref)(props.to));
+ return Promise.resolve();
+ }
+ return {
+ route,
+ href: (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => route.value.href),
+ isActive,
+ isExactActive,
+ navigate,
+ };
+}
+const RouterLinkImpl = /*#__PURE__*/ (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineComponent)({
+ name: 'RouterLink',
+ props: {
+ to: {
+ type: [String, Object],
+ required: true,
+ },
+ replace: Boolean,
+ activeClass: String,
+ // inactiveClass: String,
+ exactActiveClass: String,
+ custom: Boolean,
+ ariaCurrentValue: {
+ type: String,
+ default: 'page',
+ },
+ },
+ setup(props, { slots, attrs }) {
+ const link = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)(useLink(props));
+ const { options } = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(routerKey);
+ const elClass = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => ({
+ [getLinkClass(props.activeClass, options.linkActiveClass, 'router-link-active')]: link.isActive,
+ // [getLinkClass(
+ // props.inactiveClass,
+ // options.linkInactiveClass,
+ // 'router-link-inactive'
+ // )]: !link.isExactActive,
+ [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, 'router-link-exact-active')]: link.isExactActive,
+ }));
+ return () => {
+ const children = slots.default && slots.default(link);
+ return props.custom
+ ? children
+ : (0,vue__WEBPACK_IMPORTED_MODULE_0__.h)('a', assign({
+ 'aria-current': link.isExactActive
+ ? props.ariaCurrentValue
+ : null,
+ onClick: link.navigate,
+ href: link.href,
+ }, attrs, {
+ class: elClass.value,
+ }), children);
+ };
+ },
+});
+// export the public type for h/tsx inference
+// also to avoid inline import() in generated d.ts files
+/**
+ * Component to render a link that triggers a navigation on click.
+ */
+const RouterLink = RouterLinkImpl;
+function guardEvent(e) {
+ // don't redirect with control keys
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)
+ return;
+ // don't redirect when preventDefault called
+ if (e.defaultPrevented)
+ return;
+ // don't redirect on right click
+ if (e.button !== undefined && e.button !== 0)
+ return;
+ // don't redirect if `target="_blank"`
+ // @ts-ignore getAttribute does exist
+ if (e.currentTarget && e.currentTarget.getAttribute) {
+ // @ts-ignore getAttribute exists
+ const target = e.currentTarget.getAttribute('target');
+ if (/\b_blank\b/i.test(target))
+ return;
+ }
+ // this may be a Weex event which doesn't have this method
+ if (e.preventDefault)
+ e.preventDefault();
+ return true;
+}
+function includesParams(outer, inner) {
+ for (let key in inner) {
+ let innerValue = inner[key];
+ let outerValue = outer[key];
+ if (typeof innerValue === 'string') {
+ if (innerValue !== outerValue)
+ return false;
+ }
+ else {
+ if (!Array.isArray(outerValue) ||
+ outerValue.length !== innerValue.length ||
+ innerValue.some((value, i) => value !== outerValue[i]))
+ return false;
+ }
+ }
+ return true;
+}
+/**
+ * Get the original path value of a record by following its aliasOf
+ * @param record
+ */
+function getOriginalPath(record) {
+ return record ? (record.aliasOf ? record.aliasOf.path : record.path) : '';
+}
+/**
+ * Utility class to get the active class based on defaults.
+ * @param propClass
+ * @param globalClass
+ * @param defaultClass
+ */
+const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null
+ ? propClass
+ : globalClass != null
+ ? globalClass
+ : defaultClass;
+
+const RouterViewImpl = /*#__PURE__*/ (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineComponent)({
+ name: 'RouterView',
+ // #674 we manually inherit them
+ inheritAttrs: false,
+ props: {
+ name: {
+ type: String,
+ default: 'default',
+ },
+ route: Object,
+ },
+ setup(props, { attrs, slots }) {
+ ( true) && warnDeprecatedUsage();
+ const injectedRoute = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(routerViewLocationKey);
+ const routeToDisplay = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => props.route || injectedRoute.value);
+ const depth = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(viewDepthKey, 0);
+ const matchedRouteRef = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => routeToDisplay.value.matched[depth]);
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.provide)(viewDepthKey, depth + 1);
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.provide)(matchedRouteKey, matchedRouteRef);
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.provide)(routerViewLocationKey, routeToDisplay);
+ const viewRef = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)();
+ // watch at the same time the component instance, the route record we are
+ // rendering, and the name
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.watch)(() => [viewRef.value, matchedRouteRef.value, props.name], ([instance, to, name], [oldInstance, from, oldName]) => {
+ // copy reused instances
+ if (to) {
+ // this will update the instance for new instances as well as reused
+ // instances when navigating to a new route
+ to.instances[name] = instance;
+ // the component instance is reused for a different route or name so
+ // we copy any saved update or leave guards
+ if (from && from !== to && instance && instance === oldInstance) {
+ to.leaveGuards = from.leaveGuards;
+ to.updateGuards = from.updateGuards;
+ }
+ }
+ // trigger beforeRouteEnter next callbacks
+ if (instance &&
+ to &&
+ // if there is no instance but to and from are the same this might be
+ // the first visit
+ (!from || !isSameRouteRecord(to, from) || !oldInstance)) {
+ (to.enterCallbacks[name] || []).forEach(callback => callback(instance));
+ }
+ }, { flush: 'post' });
+ return () => {
+ const route = routeToDisplay.value;
+ const matchedRoute = matchedRouteRef.value;
+ const ViewComponent = matchedRoute && matchedRoute.components[props.name];
+ // we need the value at the time we render because when we unmount, we
+ // navigated to a different location so the value is different
+ const currentName = props.name;
+ if (!ViewComponent) {
+ return normalizeSlot(slots.default, { Component: ViewComponent, route });
+ }
+ // props from route configuration
+ const routePropsOption = matchedRoute.props[props.name];
+ const routeProps = routePropsOption
+ ? routePropsOption === true
+ ? route.params
+ : typeof routePropsOption === 'function'
+ ? routePropsOption(route)
+ : routePropsOption
+ : null;
+ const onVnodeUnmounted = vnode => {
+ // remove the instance reference to prevent leak
+ if (vnode.component.isUnmounted) {
+ matchedRoute.instances[currentName] = null;
+ }
+ };
+ const component = (0,vue__WEBPACK_IMPORTED_MODULE_0__.h)(ViewComponent, assign({}, routeProps, attrs, {
+ onVnodeUnmounted,
+ ref: viewRef,
+ }));
+ return (
+ // pass the vnode to the slot as a prop.
+ // h and both accept vnodes
+ normalizeSlot(slots.default, { Component: component, route }) ||
+ component);
+ };
+ },
+});
+function normalizeSlot(slot, data) {
+ if (!slot)
+ return null;
+ const slotContent = slot(data);
+ return slotContent.length === 1 ? slotContent[0] : slotContent;
+}
+// export the public type for h/tsx inference
+// also to avoid inline import() in generated d.ts files
+/**
+ * Component to display the current route the user is at.
+ */
+const RouterView = RouterViewImpl;
+// warn against deprecated usage with &
+// due to functional component being no longer eager in Vue 3
+function warnDeprecatedUsage() {
+ const instance = (0,vue__WEBPACK_IMPORTED_MODULE_0__.getCurrentInstance)();
+ const parentName = instance.parent && instance.parent.type.name;
+ if (parentName &&
+ (parentName === 'KeepAlive' || parentName.includes('Transition'))) {
+ const comp = parentName === 'KeepAlive' ? 'keep-alive' : 'transition';
+ warn(` can no longer be used directly inside or .\n` +
+ `Use slot props instead:\n\n` +
+ `\n` +
+ ` <${comp}>\n` +
+ ` \n` +
+ ` ${comp}>\n` +
+ ``);
+ }
+}
+
+function getDevtoolsGlobalHook() {
+ return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__;
+}
+function getTarget() {
+ // @ts-ignore
+ return typeof navigator !== 'undefined'
+ ? window
+ : typeof __webpack_require__.g !== 'undefined'
+ ? __webpack_require__.g
+ : {};
+}
+
+const HOOK_SETUP = 'devtools-plugin:setup';
+
+function setupDevtoolsPlugin(pluginDescriptor, setupFn) {
+ const hook = getDevtoolsGlobalHook();
+ if (hook) {
+ hook.emit(HOOK_SETUP, pluginDescriptor, setupFn);
+ }
+ else {
+ const target = getTarget();
+ const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || [];
+ list.push({
+ pluginDescriptor,
+ setupFn
+ });
+ }
+}
+
+function formatRouteLocation(routeLocation, tooltip) {
+ const copy = assign({}, routeLocation, {
+ // remove variables that can contain vue instances
+ matched: routeLocation.matched.map(matched => omit(matched, ['instances', 'children', 'aliasOf'])),
+ });
+ return {
+ _custom: {
+ type: null,
+ readOnly: true,
+ display: routeLocation.fullPath,
+ tooltip,
+ value: copy,
+ },
+ };
+}
+function formatDisplay(display) {
+ return {
+ _custom: {
+ display,
+ },
+ };
+}
+// to support multiple router instances
+let routerId = 0;
+function addDevtools(app, router, matcher) {
+ // Take over router.beforeEach and afterEach
+ // increment to support multiple router instances
+ const id = routerId++;
+ setupDevtoolsPlugin({
+ id: 'Router' + id ? ' ' + id : 0,
+ label: 'Router devtools',
+ app,
+ }, api => {
+ api.on.inspectComponent((payload, ctx) => {
+ if (payload.instanceData) {
+ payload.instanceData.state.push({
+ type: 'Routing',
+ key: '$route',
+ editable: false,
+ value: formatRouteLocation(router.currentRoute.value, 'Current Route'),
+ });
+ }
+ });
+ (0,vue__WEBPACK_IMPORTED_MODULE_0__.watch)(router.currentRoute, () => {
+ // refresh active state
+ refreshRoutesView();
+ // @ts-ignore
+ api.notifyComponentUpdate();
+ api.sendInspectorTree(routerInspectorId);
+ });
+ const navigationsLayerId = 'router:navigations:' + id;
+ api.addTimelineLayer({
+ id: navigationsLayerId,
+ label: `Router${id ? ' ' + id : ''} Navigations`,
+ color: 0x40a8c4,
+ });
+ // const errorsLayerId = 'router:errors'
+ // api.addTimelineLayer({
+ // id: errorsLayerId,
+ // label: 'Router Errors',
+ // color: 0xea5455,
+ // })
+ router.onError(error => {
+ api.addTimelineEvent({
+ layerId: navigationsLayerId,
+ event: {
+ // @ts-ignore
+ logType: 'error',
+ time: Date.now(),
+ data: { error },
+ },
+ });
+ });
+ router.beforeEach((to, from) => {
+ const data = {
+ guard: formatDisplay('beforeEach'),
+ from: formatRouteLocation(from, 'Current Location during this navigation'),
+ to: formatRouteLocation(to, 'Target location'),
+ };
+ api.addTimelineEvent({
+ layerId: navigationsLayerId,
+ event: {
+ time: Date.now(),
+ meta: {},
+ data,
+ },
+ });
+ });
+ router.afterEach((to, from, failure) => {
+ const data = {
+ guard: formatDisplay('afterEach'),
+ };
+ if (failure) {
+ data.failure = {
+ _custom: {
+ type: Error,
+ readOnly: true,
+ display: failure ? failure.message : '',
+ tooltip: 'Navigation Failure',
+ value: failure,
+ },
+ };
+ data.status = formatDisplay('❌');
+ }
+ else {
+ data.status = formatDisplay('✅');
+ }
+ // we set here to have the right order
+ data.from = formatRouteLocation(from, 'Current Location during this navigation');
+ data.to = formatRouteLocation(to, 'Target location');
+ api.addTimelineEvent({
+ layerId: navigationsLayerId,
+ event: {
+ time: Date.now(),
+ data,
+ // @ts-ignore
+ logType: failure ? 'warning' : 'default',
+ meta: {},
+ },
+ });
+ });
+ /**
+ * Inspector of Existing routes
+ */
+ const routerInspectorId = 'router-inspector:' + id;
+ api.addInspector({
+ id: routerInspectorId,
+ label: 'Routes' + (id ? ' ' + id : ''),
+ icon: 'book',
+ treeFilterPlaceholder: 'Search routes',
+ });
+ function refreshRoutesView() {
+ // the routes view isn't active
+ if (!activeRoutesPayload)
+ return;
+ const payload = activeRoutesPayload;
+ // children routes will appear as nested
+ let routes = matcher.getRoutes().filter(route => !route.parent);
+ // reset match state to false
+ routes.forEach(resetMatchStateOnRouteRecord);
+ // apply a match state if there is a payload
+ if (payload.filter) {
+ routes = routes.filter(route =>
+ // save matches state based on the payload
+ isRouteMatching(route, payload.filter.toLowerCase()));
+ }
+ // mark active routes
+ routes.forEach(route => markRouteRecordActive(route, router.currentRoute.value));
+ payload.rootNodes = routes.map(formatRouteRecordForInspector);
+ }
+ let activeRoutesPayload;
+ api.on.getInspectorTree(payload => {
+ activeRoutesPayload = payload;
+ if (payload.app === app && payload.inspectorId === routerInspectorId) {
+ refreshRoutesView();
+ }
+ });
+ /**
+ * Display information about the currently selected route record
+ */
+ api.on.getInspectorState(payload => {
+ if (payload.app === app && payload.inspectorId === routerInspectorId) {
+ const routes = matcher.getRoutes();
+ const route = routes.find(route => route.record.__vd_id === payload.nodeId);
+ if (route) {
+ payload.state = {
+ options: formatRouteRecordMatcherForStateInspector(route),
+ };
+ }
+ }
+ });
+ api.sendInspectorTree(routerInspectorId);
+ api.sendInspectorState(routerInspectorId);
+ });
+}
+function modifierForKey(key) {
+ if (key.optional) {
+ return key.repeatable ? '*' : '?';
+ }
+ else {
+ return key.repeatable ? '+' : '';
+ }
+}
+function formatRouteRecordMatcherForStateInspector(route) {
+ const { record } = route;
+ const fields = [
+ { editable: false, key: 'path', value: record.path },
+ ];
+ if (record.name != null) {
+ fields.push({
+ editable: false,
+ key: 'name',
+ value: record.name,
+ });
+ }
+ fields.push({ editable: false, key: 'regexp', value: route.re });
+ if (route.keys.length) {
+ fields.push({
+ editable: false,
+ key: 'keys',
+ value: {
+ _custom: {
+ type: null,
+ readOnly: true,
+ display: route.keys
+ .map(key => `${key.name}${modifierForKey(key)}`)
+ .join(' '),
+ tooltip: 'Param keys',
+ value: route.keys,
+ },
+ },
+ });
+ }
+ if (record.redirect != null) {
+ fields.push({
+ editable: false,
+ key: 'redirect',
+ value: record.redirect,
+ });
+ }
+ if (route.alias.length) {
+ fields.push({
+ editable: false,
+ key: 'aliases',
+ value: route.alias.map(alias => alias.record.path),
+ });
+ }
+ fields.push({
+ key: 'score',
+ editable: false,
+ value: {
+ _custom: {
+ type: null,
+ readOnly: true,
+ display: route.score.map(score => score.join(', ')).join(' | '),
+ tooltip: 'Score used to sort routes',
+ value: route.score,
+ },
+ },
+ });
+ return fields;
+}
+/**
+ * Extracted from tailwind palette
+ */
+const PINK_500 = 0xec4899;
+const BLUE_600 = 0x2563eb;
+const LIME_500 = 0x84cc16;
+const CYAN_400 = 0x22d3ee;
+const ORANGE_400 = 0xfb923c;
+// const GRAY_100 = 0xf4f4f5
+const DARK = 0x666666;
+function formatRouteRecordForInspector(route) {
+ const tags = [];
+ const { record } = route;
+ if (record.name != null) {
+ tags.push({
+ label: String(record.name),
+ textColor: 0,
+ backgroundColor: CYAN_400,
+ });
+ }
+ if (record.aliasOf) {
+ tags.push({
+ label: 'alias',
+ textColor: 0,
+ backgroundColor: ORANGE_400,
+ });
+ }
+ if (route.__vd_match) {
+ tags.push({
+ label: 'matches',
+ textColor: 0,
+ backgroundColor: PINK_500,
+ });
+ }
+ if (route.__vd_exactActive) {
+ tags.push({
+ label: 'exact',
+ textColor: 0,
+ backgroundColor: LIME_500,
+ });
+ }
+ if (route.__vd_active) {
+ tags.push({
+ label: 'active',
+ textColor: 0,
+ backgroundColor: BLUE_600,
+ });
+ }
+ if (record.redirect) {
+ tags.push({
+ label: 'redirect: ' +
+ (typeof record.redirect === 'string' ? record.redirect : 'Object'),
+ textColor: 0xffffff,
+ backgroundColor: DARK,
+ });
+ }
+ // add an id to be able to select it. Using the `path` is not possible because
+ // empty path children would collide with their parents
+ let id = String(routeRecordId++);
+ record.__vd_id = id;
+ return {
+ id,
+ label: record.path,
+ tags,
+ // @ts-ignore
+ children: route.children.map(formatRouteRecordForInspector),
+ };
+}
+// incremental id for route records and inspector state
+let routeRecordId = 0;
+const EXTRACT_REGEXP_RE = /^\/(.*)\/([a-z]*)$/;
+function markRouteRecordActive(route, currentRoute) {
+ // no route will be active if matched is empty
+ // reset the matching state
+ const isExactActive = currentRoute.matched.length &&
+ isSameRouteRecord(currentRoute.matched[currentRoute.matched.length - 1], route.record);
+ route.__vd_exactActive = route.__vd_active = isExactActive;
+ if (!isExactActive) {
+ route.__vd_active = currentRoute.matched.some(match => isSameRouteRecord(match, route.record));
+ }
+ route.children.forEach(childRoute => markRouteRecordActive(childRoute, currentRoute));
+}
+function resetMatchStateOnRouteRecord(route) {
+ route.__vd_match = false;
+ route.children.forEach(resetMatchStateOnRouteRecord);
+}
+function isRouteMatching(route, filter) {
+ const found = String(route.re).match(EXTRACT_REGEXP_RE);
+ route.__vd_match = false;
+ if (!found || found.length < 3) {
+ return false;
+ }
+ // use a regexp without $ at the end to match nested routes better
+ const nonEndingRE = new RegExp(found[1].replace(/\$$/, ''), found[2]);
+ if (nonEndingRE.test(filter)) {
+ // mark children as matches
+ route.children.forEach(child => isRouteMatching(child, filter));
+ // exception case: `/`
+ if (route.record.path !== '/' || filter === '/') {
+ route.__vd_match = route.re.test(filter);
+ return true;
+ }
+ // hide the / route
+ return false;
+ }
+ const path = route.record.path.toLowerCase();
+ const decodedPath = decode(path);
+ // also allow partial matching on the path
+ if (!filter.startsWith('/') &&
+ (decodedPath.includes(filter) || path.includes(filter)))
+ return true;
+ if (decodedPath.startsWith(filter) || path.startsWith(filter))
+ return true;
+ if (route.record.name && String(route.record.name).includes(filter))
+ return true;
+ return route.children.some(child => isRouteMatching(child, filter));
+}
+function omit(obj, keys) {
+ const ret = {};
+ for (let key in obj) {
+ if (!keys.includes(key)) {
+ // @ts-ignore
+ ret[key] = obj[key];
+ }
+ }
+ return ret;
+}
+
+/**
+ * Creates a Router instance that can be used by a Vue app.
+ *
+ * @param options - {@link RouterOptions}
+ */
+function createRouter(options) {
+ const matcher = createRouterMatcher(options.routes, options);
+ let parseQuery$1 = options.parseQuery || parseQuery;
+ let stringifyQuery$1 = options.stringifyQuery || stringifyQuery;
+ let routerHistory = options.history;
+ const beforeGuards = useCallbacks();
+ const beforeResolveGuards = useCallbacks();
+ const afterGuards = useCallbacks();
+ const currentRoute = (0,vue__WEBPACK_IMPORTED_MODULE_0__.shallowRef)(START_LOCATION_NORMALIZED);
+ let pendingLocation = START_LOCATION_NORMALIZED;
+ // leave the scrollRestoration if no scrollBehavior is provided
+ if (isBrowser && options.scrollBehavior && 'scrollRestoration' in history) {
+ history.scrollRestoration = 'manual';
+ }
+ const normalizeParams = applyToParams.bind(null, paramValue => '' + paramValue);
+ const encodeParams = applyToParams.bind(null, encodeParam);
+ const decodeParams = applyToParams.bind(null, decode);
+ function addRoute(parentOrRoute, route) {
+ let parent;
+ let record;
+ if (isRouteName(parentOrRoute)) {
+ parent = matcher.getRecordMatcher(parentOrRoute);
+ record = route;
+ }
+ else {
+ record = parentOrRoute;
+ }
+ return matcher.addRoute(record, parent);
+ }
+ function removeRoute(name) {
+ let recordMatcher = matcher.getRecordMatcher(name);
+ if (recordMatcher) {
+ matcher.removeRoute(recordMatcher);
+ }
+ else if ((true)) {
+ warn(`Cannot remove non-existent route "${String(name)}"`);
+ }
+ }
+ function getRoutes() {
+ return matcher.getRoutes().map(routeMatcher => routeMatcher.record);
+ }
+ function hasRoute(name) {
+ return !!matcher.getRecordMatcher(name);
+ }
+ function resolve(rawLocation, currentLocation) {
+ // const objectLocation = routerLocationAsObject(rawLocation)
+ // we create a copy to modify it later
+ currentLocation = assign({}, currentLocation || currentRoute.value);
+ if (typeof rawLocation === 'string') {
+ let locationNormalized = parseURL(parseQuery$1, rawLocation, currentLocation.path);
+ let matchedRoute = matcher.resolve({ path: locationNormalized.path }, currentLocation);
+ let href = routerHistory.createHref(locationNormalized.fullPath);
+ if ((true)) {
+ if (href.startsWith('//'))
+ warn(`Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.`);
+ else if (!matchedRoute.matched.length) {
+ warn(`No match found for location with path "${rawLocation}"`);
+ }
+ }
+ // locationNormalized is always a new object
+ return assign(locationNormalized, matchedRoute, {
+ params: decodeParams(matchedRoute.params),
+ hash: decode(locationNormalized.hash),
+ redirectedFrom: undefined,
+ href,
+ });
+ }
+ let matcherLocation;
+ // path could be relative in object as well
+ if ('path' in rawLocation) {
+ if (( true) &&
+ 'params' in rawLocation &&
+ !('name' in rawLocation) &&
+ Object.keys(rawLocation.params).length) {
+ warn(`Path "${rawLocation.path}" was passed with params but they will be ignored. Use a named route alongside params instead.`);
+ }
+ matcherLocation = assign({}, rawLocation, {
+ path: parseURL(parseQuery$1, rawLocation.path, currentLocation.path).path,
+ });
+ }
+ else {
+ // pass encoded values to the matcher so it can produce encoded path and fullPath
+ matcherLocation = assign({}, rawLocation, {
+ params: encodeParams(rawLocation.params),
+ });
+ // current location params are decoded, we need to encode them in case the
+ // matcher merges the params
+ currentLocation.params = encodeParams(currentLocation.params);
+ }
+ let matchedRoute = matcher.resolve(matcherLocation, currentLocation);
+ const hash = rawLocation.hash || '';
+ if (( true) && hash && !hash.startsWith('#')) {
+ warn(`A \`hash\` should always start with the character "#". Replace "${hash}" with "#${hash}".`);
+ }
+ // decoding them) the matcher might have merged current location params so
+ // we need to run the decoding again
+ matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params));
+ const fullPath = stringifyURL(stringifyQuery$1, assign({}, rawLocation, {
+ hash: encodeHash(hash),
+ path: matchedRoute.path,
+ }));
+ let href = routerHistory.createHref(fullPath);
+ if ((true)) {
+ if (href.startsWith('//')) {
+ warn(`Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.`);
+ }
+ else if (!matchedRoute.matched.length) {
+ warn(`No match found for location with path "${'path' in rawLocation ? rawLocation.path : rawLocation}"`);
+ }
+ }
+ return assign({
+ fullPath,
+ // keep the hash encoded so fullPath is effectively path + encodedQuery +
+ // hash
+ hash,
+ query:
+ // if the user is using a custom query lib like qs, we might have
+ // nested objects, so we keep the query as is, meaning it can contain
+ // numbers at `$route.query`, but at the point, the user will have to
+ // use their own type anyway.
+ // https://github.com/vuejs/vue-router-next/issues/328#issuecomment-649481567
+ stringifyQuery$1 === stringifyQuery
+ ? normalizeQuery(rawLocation.query)
+ : rawLocation.query,
+ }, matchedRoute, {
+ redirectedFrom: undefined,
+ href,
+ });
+ }
+ function locationAsObject(to) {
+ return typeof to === 'string'
+ ? parseURL(parseQuery$1, to, currentRoute.value.path)
+ : assign({}, to);
+ }
+ function checkCanceledNavigation(to, from) {
+ if (pendingLocation !== to) {
+ return createRouterError(8 /* NAVIGATION_CANCELLED */, {
+ from,
+ to,
+ });
+ }
+ }
+ function push(to) {
+ return pushWithRedirect(to);
+ }
+ function replace(to) {
+ return push(assign(locationAsObject(to), { replace: true }));
+ }
+ function handleRedirectRecord(to) {
+ const lastMatched = to.matched[to.matched.length - 1];
+ if (lastMatched && lastMatched.redirect) {
+ const { redirect } = lastMatched;
+ let newTargetLocation = typeof redirect === 'function' ? redirect(to) : redirect;
+ if (typeof newTargetLocation === 'string') {
+ newTargetLocation =
+ newTargetLocation.indexOf('?') > -1 ||
+ newTargetLocation.indexOf('#') > -1
+ ? (newTargetLocation = locationAsObject(newTargetLocation))
+ : { path: newTargetLocation };
+ }
+ if (( true) &&
+ !('path' in newTargetLocation) &&
+ !('name' in newTargetLocation)) {
+ warn(`Invalid redirect found:\n${JSON.stringify(newTargetLocation, null, 2)}\n when navigating to "${to.fullPath}". A redirect must contain a name or path. This will break in production.`);
+ throw new Error('Invalid redirect');
+ }
+ return assign({
+ query: to.query,
+ hash: to.hash,
+ params: to.params,
+ }, newTargetLocation);
+ }
+ }
+ function pushWithRedirect(to, redirectedFrom) {
+ const targetLocation = (pendingLocation = resolve(to));
+ const from = currentRoute.value;
+ const data = to.state;
+ const force = to.force;
+ // to could be a string where `replace` is a function
+ const replace = to.replace === true;
+ const shouldRedirect = handleRedirectRecord(targetLocation);
+ if (shouldRedirect)
+ return pushWithRedirect(assign(locationAsObject(shouldRedirect), {
+ state: data,
+ force,
+ replace,
+ }),
+ // keep original redirectedFrom if it exists
+ redirectedFrom || targetLocation);
+ // if it was a redirect we already called `pushWithRedirect` above
+ const toLocation = targetLocation;
+ toLocation.redirectedFrom = redirectedFrom;
+ let failure;
+ if (!force && isSameRouteLocation(stringifyQuery$1, from, targetLocation)) {
+ failure = createRouterError(16 /* NAVIGATION_DUPLICATED */, { to: toLocation, from });
+ // trigger scroll to allow scrolling to the same anchor
+ handleScroll(from, from,
+ // this is a push, the only way for it to be triggered from a
+ // history.listen is with a redirect, which makes it become a push
+ true,
+ // This cannot be the first navigation because the initial location
+ // cannot be manually navigated to
+ false);
+ }
+ return (failure ? Promise.resolve(failure) : navigate(toLocation, from))
+ .catch((error) => isNavigationFailure(error)
+ ? error
+ : // reject any unknown error
+ triggerError(error))
+ .then((failure) => {
+ if (failure) {
+ if (isNavigationFailure(failure, 2 /* NAVIGATION_GUARD_REDIRECT */)) {
+ if (( true) &&
+ // we are redirecting to the same location we were already at
+ isSameRouteLocation(stringifyQuery$1, resolve(failure.to), toLocation) &&
+ // and we have done it a couple of times
+ redirectedFrom &&
+ // @ts-ignore
+ (redirectedFrom._count = redirectedFrom._count
+ ? // @ts-ignore
+ redirectedFrom._count + 1
+ : 1) > 10) {
+ warn(`Detected an infinite redirection in a navigation guard when going from "${from.fullPath}" to "${toLocation.fullPath}". Aborting to avoid a Stack Overflow. This will break in production if not fixed.`);
+ return Promise.reject(new Error('Infinite redirect in navigation guard'));
+ }
+ return pushWithRedirect(
+ // keep options
+ assign(locationAsObject(failure.to), {
+ state: data,
+ force,
+ replace,
+ }),
+ // preserve the original redirectedFrom if any
+ redirectedFrom || toLocation);
+ }
+ }
+ else {
+ // if we fail we don't finalize the navigation
+ failure = finalizeNavigation(toLocation, from, true, replace, data);
+ }
+ triggerAfterEach(toLocation, from, failure);
+ return failure;
+ });
+ }
+ /**
+ * Helper to reject and skip all navigation guards if a new navigation happened
+ * @param to
+ * @param from
+ */
+ function checkCanceledNavigationAndReject(to, from) {
+ const error = checkCanceledNavigation(to, from);
+ return error ? Promise.reject(error) : Promise.resolve();
+ }
+ // TODO: refactor the whole before guards by internally using router.beforeEach
+ function navigate(to, from) {
+ let guards;
+ const [leavingRecords, updatingRecords, enteringRecords,] = extractChangingRecords(to, from);
+ // all components here have been resolved once because we are leaving
+ guards = extractComponentsGuards(leavingRecords.reverse(), 'beforeRouteLeave', to, from);
+ // leavingRecords is already reversed
+ for (const record of leavingRecords) {
+ record.leaveGuards.forEach(guard => {
+ guards.push(guardToPromiseFn(guard, to, from));
+ });
+ }
+ const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(null, to, from);
+ guards.push(canceledNavigationCheck);
+ // run the queue of per route beforeRouteLeave guards
+ return (runGuardQueue(guards)
+ .then(() => {
+ // check global guards beforeEach
+ guards = [];
+ for (const guard of beforeGuards.list()) {
+ guards.push(guardToPromiseFn(guard, to, from));
+ }
+ guards.push(canceledNavigationCheck);
+ return runGuardQueue(guards);
+ })
+ .then(() => {
+ // check in components beforeRouteUpdate
+ guards = extractComponentsGuards(updatingRecords, 'beforeRouteUpdate', to, from);
+ for (const record of updatingRecords) {
+ record.updateGuards.forEach(guard => {
+ guards.push(guardToPromiseFn(guard, to, from));
+ });
+ }
+ guards.push(canceledNavigationCheck);
+ // run the queue of per route beforeEnter guards
+ return runGuardQueue(guards);
+ })
+ .then(() => {
+ // check the route beforeEnter
+ guards = [];
+ for (const record of to.matched) {
+ // do not trigger beforeEnter on reused views
+ if (record.beforeEnter && from.matched.indexOf(record) < 0) {
+ if (Array.isArray(record.beforeEnter)) {
+ for (const beforeEnter of record.beforeEnter)
+ guards.push(guardToPromiseFn(beforeEnter, to, from));
+ }
+ else {
+ guards.push(guardToPromiseFn(record.beforeEnter, to, from));
+ }
+ }
+ }
+ guards.push(canceledNavigationCheck);
+ // run the queue of per route beforeEnter guards
+ return runGuardQueue(guards);
+ })
+ .then(() => {
+ // NOTE: at this point to.matched is normalized and does not contain any () => Promise
+ // clear existing enterCallbacks, these are added by extractComponentsGuards
+ to.matched.forEach(record => (record.enterCallbacks = {}));
+ // check in-component beforeRouteEnter
+ guards = extractComponentsGuards(enteringRecords, 'beforeRouteEnter', to, from);
+ guards.push(canceledNavigationCheck);
+ // run the queue of per route beforeEnter guards
+ return runGuardQueue(guards);
+ })
+ .then(() => {
+ // check global guards beforeResolve
+ guards = [];
+ for (const guard of beforeResolveGuards.list()) {
+ guards.push(guardToPromiseFn(guard, to, from));
+ }
+ guards.push(canceledNavigationCheck);
+ return runGuardQueue(guards);
+ })
+ // catch any navigation canceled
+ .catch(err => isNavigationFailure(err, 8 /* NAVIGATION_CANCELLED */)
+ ? err
+ : Promise.reject(err)));
+ }
+ function triggerAfterEach(to, from, failure) {
+ // navigation is confirmed, call afterGuards
+ // TODO: wrap with error handlers
+ for (const guard of afterGuards.list())
+ guard(to, from, failure);
+ }
+ /**
+ * - Cleans up any navigation guards
+ * - Changes the url if necessary
+ * - Calls the scrollBehavior
+ */
+ function finalizeNavigation(toLocation, from, isPush, replace, data) {
+ // a more recent navigation took place
+ const error = checkCanceledNavigation(toLocation, from);
+ if (error)
+ return error;
+ // only consider as push if it's not the first navigation
+ const isFirstNavigation = from === START_LOCATION_NORMALIZED;
+ const state = !isBrowser ? {} : history.state;
+ // change URL only if the user did a push/replace and if it's not the initial navigation because
+ // it's just reflecting the url
+ if (isPush) {
+ // on the initial navigation, we want to reuse the scroll position from
+ // history state if it exists
+ if (replace || isFirstNavigation)
+ routerHistory.replace(toLocation.fullPath, assign({
+ scroll: isFirstNavigation && state && state.scroll,
+ }, data));
+ else
+ routerHistory.push(toLocation.fullPath, data);
+ }
+ // accept current navigation
+ currentRoute.value = toLocation;
+ handleScroll(toLocation, from, isPush, isFirstNavigation);
+ markAsReady();
+ }
+ let removeHistoryListener;
+ // attach listener to history to trigger navigations
+ function setupListeners() {
+ removeHistoryListener = routerHistory.listen((to, _from, info) => {
+ // cannot be a redirect route because it was in history
+ let toLocation = resolve(to);
+ // due to dynamic routing, and to hash history with manual navigation
+ // (manually changing the url or calling history.hash = '#/somewhere'),
+ // there could be a redirect record in history
+ const shouldRedirect = handleRedirectRecord(toLocation);
+ if (shouldRedirect) {
+ pushWithRedirect(assign(shouldRedirect, { replace: true }), toLocation).catch(noop);
+ return;
+ }
+ pendingLocation = toLocation;
+ const from = currentRoute.value;
+ // TODO: should be moved to web history?
+ if (isBrowser) {
+ saveScrollPosition(getScrollKey(from.fullPath, info.delta), computeScrollPosition());
+ }
+ navigate(toLocation, from)
+ .catch((error) => {
+ if (isNavigationFailure(error, 4 /* NAVIGATION_ABORTED */ | 8 /* NAVIGATION_CANCELLED */)) {
+ return error;
+ }
+ if (isNavigationFailure(error, 2 /* NAVIGATION_GUARD_REDIRECT */)) {
+ // Here we could call if (info.delta) routerHistory.go(-info.delta,
+ // false) but this is bug prone as we have no way to wait the
+ // navigation to be finished before calling pushWithRedirect. Using
+ // a setTimeout of 16ms seems to work but there is not guarantee for
+ // it to work on every browser. So Instead we do not restore the
+ // history entry and trigger a new navigation as requested by the
+ // navigation guard.
+ // the error is already handled by router.push we just want to avoid
+ // logging the error
+ pushWithRedirect(error.to, toLocation
+ // avoid an uncaught rejection, let push call triggerError
+ ).catch(noop);
+ // avoid the then branch
+ return Promise.reject();
+ }
+ // do not restore history on unknown direction
+ if (info.delta)
+ routerHistory.go(-info.delta, false);
+ // unrecognized error, transfer to the global handler
+ return triggerError(error);
+ })
+ .then((failure) => {
+ failure =
+ failure ||
+ finalizeNavigation(
+ // after navigation, all matched components are resolved
+ toLocation, from, false);
+ // revert the navigation
+ if (failure && info.delta)
+ routerHistory.go(-info.delta, false);
+ triggerAfterEach(toLocation, from, failure);
+ })
+ .catch(noop);
+ });
+ }
+ // Initialization and Errors
+ let readyHandlers = useCallbacks();
+ let errorHandlers = useCallbacks();
+ let ready;
+ /**
+ * Trigger errorHandlers added via onError and throws the error as well
+ * @param error - error to throw
+ * @returns the error as a rejected promise
+ */
+ function triggerError(error) {
+ markAsReady(error);
+ errorHandlers.list().forEach(handler => handler(error));
+ return Promise.reject(error);
+ }
+ function isReady() {
+ if (ready && currentRoute.value !== START_LOCATION_NORMALIZED)
+ return Promise.resolve();
+ return new Promise((resolve, reject) => {
+ readyHandlers.add([resolve, reject]);
+ });
+ }
+ /**
+ * Mark the router as ready, resolving the promised returned by isReady(). Can
+ * only be called once, otherwise does nothing.
+ * @param err - optional error
+ */
+ function markAsReady(err) {
+ if (ready)
+ return;
+ ready = true;
+ setupListeners();
+ readyHandlers
+ .list()
+ .forEach(([resolve, reject]) => (err ? reject(err) : resolve()));
+ readyHandlers.reset();
+ }
+ // Scroll behavior
+ function handleScroll(to, from, isPush, isFirstNavigation) {
+ const { scrollBehavior } = options;
+ if (!isBrowser || !scrollBehavior)
+ return Promise.resolve();
+ let scrollPosition = (!isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0))) ||
+ ((isFirstNavigation || !isPush) &&
+ history.state &&
+ history.state.scroll) ||
+ null;
+ return (0,vue__WEBPACK_IMPORTED_MODULE_0__.nextTick)()
+ .then(() => scrollBehavior(to, from, scrollPosition))
+ .then(position => position && scrollToPosition(position))
+ .catch(triggerError);
+ }
+ const go = (delta) => routerHistory.go(delta);
+ let started;
+ const installedApps = new Set();
+ const router = {
+ currentRoute,
+ addRoute,
+ removeRoute,
+ hasRoute,
+ getRoutes,
+ resolve,
+ options,
+ push,
+ replace,
+ go,
+ back: () => go(-1),
+ forward: () => go(1),
+ beforeEach: beforeGuards.add,
+ beforeResolve: beforeResolveGuards.add,
+ afterEach: afterGuards.add,
+ onError: errorHandlers.add,
+ isReady,
+ install(app) {
+ const router = this;
+ app.component('RouterLink', RouterLink);
+ app.component('RouterView', RouterView);
+ app.config.globalProperties.$router = router;
+ Object.defineProperty(app.config.globalProperties, '$route', {
+ get: () => (0,vue__WEBPACK_IMPORTED_MODULE_0__.unref)(currentRoute),
+ });
+ // this initial navigation is only necessary on client, on server it doesn't
+ // make sense because it will create an extra unnecessary navigation and could
+ // lead to problems
+ if (isBrowser &&
+ // used for the initial navigation client side to avoid pushing
+ // multiple times when the router is used in multiple apps
+ !started &&
+ currentRoute.value === START_LOCATION_NORMALIZED) {
+ // see above
+ started = true;
+ push(routerHistory.location).catch(err => {
+ if ((true))
+ warn('Unexpected error when starting the router:', err);
+ });
+ }
+ const reactiveRoute = {};
+ for (let key in START_LOCATION_NORMALIZED) {
+ // @ts-ignore: the key matches
+ reactiveRoute[key] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => currentRoute.value[key]);
+ }
+ app.provide(routerKey, router);
+ app.provide(routeLocationKey, (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)(reactiveRoute));
+ app.provide(routerViewLocationKey, currentRoute);
+ let unmountApp = app.unmount;
+ installedApps.add(app);
+ app.unmount = function () {
+ installedApps.delete(app);
+ if (installedApps.size < 1) {
+ removeHistoryListener();
+ currentRoute.value = START_LOCATION_NORMALIZED;
+ started = false;
+ ready = false;
+ }
+ unmountApp.call(this, arguments);
+ };
+ if (true) {
+ addDevtools(app, router, matcher);
+ }
+ },
+ };
+ return router;
+}
+function runGuardQueue(guards) {
+ return guards.reduce((promise, guard) => promise.then(() => guard()), Promise.resolve());
+}
+function extractChangingRecords(to, from) {
+ const leavingRecords = [];
+ const updatingRecords = [];
+ const enteringRecords = [];
+ const len = Math.max(from.matched.length, to.matched.length);
+ for (let i = 0; i < len; i++) {
+ const recordFrom = from.matched[i];
+ if (recordFrom) {
+ if (to.matched.indexOf(recordFrom) < 0)
+ leavingRecords.push(recordFrom);
+ else
+ updatingRecords.push(recordFrom);
+ }
+ const recordTo = to.matched[i];
+ if (recordTo) {
+ // the type doesn't matter because we are comparing per reference
+ if (from.matched.indexOf(recordTo) < 0)
+ enteringRecords.push(recordTo);
+ }
+ }
+ return [leavingRecords, updatingRecords, enteringRecords];
+}
+
+/**
+ * Returns the router instance. Equivalent to using `$router` inside
+ * templates.
+ */
+function useRouter() {
+ return (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(routerKey);
+}
+/**
+ * Returns the current route location. Equivalent to using `$route` inside
+ * templates.
+ */
+function useRoute() {
+ return (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(routeLocationKey);
+}
+
+
+
+
/***/ }),
/***/ "./node_modules/vue/dist/vue.esm-bundler.js":
@@ -36191,6 +39663,6 @@ const {
/******/
/************************************************************************/
/******/ // run startup
-/******/ return __webpack_require__.x();
+/******/ __webpack_require__.x();
/******/ })()
;
\ No newline at end of file
diff --git a/resources/js/app.js b/resources/js/app.js
index a5195f33..e33e506a 100644
--- a/resources/js/app.js
+++ b/resources/js/app.js
@@ -1,14 +1,27 @@
require("./bootstrap");
import { createApp } from "vue";
+import { createRouter, createWebHashHistory } from "vue-router";
import store from "./store/index";
+
import MainIndex from "./components/MainIndex.vue";
+import Navbar from "./components/Header/Navbar.vue";
+import Products from "./components/Products/Products.vue";
+
+const routes = [
+ { path: "/", component: Navbar },
+ { path: "/products", component: Products },
+];
+
+const router = createRouter({
+ history: createWebHashHistory(),
+ routes,
+});
createApp({
- components: { MainIndex },
+ components: { Navbar, MainIndex, Products },
})
.use(store)
+ .use(router)
.mount("#app");
-
-//app.use(store);
diff --git a/resources/js/components/Footer/Footer.vue b/resources/js/components/Footer/Footer.vue
new file mode 100644
index 00000000..35b22077
--- /dev/null
+++ b/resources/js/components/Footer/Footer.vue
@@ -0,0 +1,13 @@
+
+ Default footer
+
+
+
+
+
diff --git a/resources/js/components/Header/Layout.vue b/resources/js/components/Header/Layout.vue
new file mode 100644
index 00000000..75ad45d8
--- /dev/null
+++ b/resources/js/components/Header/Layout.vue
@@ -0,0 +1,18 @@
+
+
+ CONTENT
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/components/Header/MobileMenu.vue b/resources/js/components/Header/MobileMenu.vue
new file mode 100644
index 00000000..4d9c440b
--- /dev/null
+++ b/resources/js/components/Header/MobileMenu.vue
@@ -0,0 +1,7 @@
+Mobile menu
+
+
+
+
diff --git a/resources/js/components/Header/Navbar.vue b/resources/js/components/Header/Navbar.vue
index a596de0b..1edbde65 100644
--- a/resources/js/components/Header/Navbar.vue
+++ b/resources/js/components/Header/Navbar.vue
@@ -1,47 +1,85 @@
-
-
+
+
+
+
+

+
+
+ MobileMenu
+
-
-
- Shopping Cart
-
-
-
- Checkout
-
+
+
+
+
+
-
-
+
+
+
diff --git a/resources/js/components/Layouts/Layout.vue b/resources/js/components/Layouts/Layout.vue
new file mode 100644
index 00000000..5e0d4aa9
--- /dev/null
+++ b/resources/js/components/Layouts/Layout.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/resources/js/components/Products/Products.vue b/resources/js/components/Products/Products.vue
new file mode 100644
index 00000000..7aba153f
--- /dev/null
+++ b/resources/js/components/Products/Products.vue
@@ -0,0 +1,7 @@
+Show all products
+
+
+
+