diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index d8872c9..1172589 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -13,7 +13,7 @@ module.exports = {
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
- project: "tsconfig.lint.json",
+ project: "tsconfig.node.json",
tsconfigRootDir: __dirname,
},
plugins: ['react-refresh', 'prettier'],
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 6cf74e0..3a88c20 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -25,9 +25,29 @@ jobs:
env:
CI: true
+ cypress:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ browsers:
+ - chrome
+ - firefox
+ - edge
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Cypress run
+ uses: cypress-io/github-action@v6
+ with:
+ config-file: 'test/component/cypress.config.ts'
+ start: npm run vue:component:serve
+ browser: ${{ matrix.browsers }}
+
status-checks:
name: status-checks
- needs: [build]
+ needs:
+ - build
+ - cypress
permissions:
contents: none
if: always()
@@ -38,7 +58,7 @@ jobs:
run: |
echo 'Configuration for Status checks that are required'
echo '${{ toJSON(needs) }}'
- if [[ ('skipped' == '${{ needs.build.result }}') || ('success' == '${{ needs.build.result }}') ]]; then
+ if [[ (('skipped' == '${{ needs.build.result }}') || ('success' == '${{ needs.build.result }}')) && (('skipped' == '${{ needs.cypress.result }}') || ('success' == '${{ needs.cypress.result }}')) ]]; then
exit 0
fi
exit 1
diff --git a/config/react/.env b/config/react/.env
new file mode 100644
index 0000000..08634f5
--- /dev/null
+++ b/config/react/.env
@@ -0,0 +1 @@
+VITE_FWK=react
diff --git a/config/vue/.env b/config/vue/.env
new file mode 100644
index 0000000..ac61d6b
--- /dev/null
+++ b/config/vue/.env
@@ -0,0 +1 @@
+VITE_FWK=vue
diff --git a/index.html b/index.html
index b7a8e45..76e5ae4 100644
--- a/index.html
+++ b/index.html
@@ -1,13 +1,13 @@
-
+
- Library using React
+ Library
-
-
+
+
diff --git a/package-lock.json b/package-lock.json
index 03ae99b..45d4318 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,11 +10,14 @@
"dependencies": {
"i18next": "^23.2.11",
"i18next-browser-languagedetector": "^8.0.0",
+ "i18next-vue": "^4.0.0",
"piqure": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.1",
- "react-router-dom": "^6.14.2"
+ "react-router-dom": "^6.14.2",
+ "vue": "^3.4.36",
+ "vue-router": "^4.4.3"
},
"devDependencies": {
"@types/react": "^18.2.17",
@@ -23,6 +26,7 @@
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"@vitejs/plugin-react": "^4.0.1",
+ "@vitejs/plugin-vue": "^5.1.2",
"@vitest/coverage-v8": "^2.0.5",
"axios": "^1.4.0",
"cypress": "^13.13.2",
@@ -35,7 +39,8 @@
"start-server-and-test": "^2.0.0",
"typescript": "^5.0.2",
"vite": "^5.4.0",
- "vitest": "^2.0.5"
+ "vitest": "^2.0.5",
+ "vue-tsc": "^2.0.29"
}
},
"node_modules/@ampproject/remapping": {
@@ -209,7 +214,6 @@
"version": "7.24.8",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
"integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
- "dev": true,
"engines": {
"node": ">=6.9.0"
}
@@ -218,7 +222,6 @@
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
- "dev": true,
"engines": {
"node": ">=6.9.0"
}
@@ -264,7 +267,6 @@
"version": "7.25.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz",
"integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==",
- "dev": true,
"dependencies": {
"@babel/types": "^7.25.2"
},
@@ -352,7 +354,6 @@
"version": "7.25.2",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
"integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
- "dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.24.8",
"@babel/helper-validator-identifier": "^7.24.7",
@@ -1125,8 +1126,7 @@
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
- "dev": true
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
@@ -1816,6 +1816,19 @@
"vite": "^4.2.0 || ^5.0.0"
}
},
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.2.tgz",
+ "integrity": "sha512-nY9IwH12qeiJqumTCLJLE7IiNx7HZ39cbHaysEUd+Myvbz9KAqd2yq+U01Kab1R/H1BmiyM2ShTYlNH32Fzo3A==",
+ "dev": true,
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0",
+ "vue": "^3.2.25"
+ }
+ },
"node_modules/@vitest/coverage-v8": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.0.5.tgz",
@@ -1923,6 +1936,183 @@
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/@volar/language-core": {
+ "version": "2.4.0-alpha.18",
+ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0-alpha.18.tgz",
+ "integrity": "sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==",
+ "dev": true,
+ "dependencies": {
+ "@volar/source-map": "2.4.0-alpha.18"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.0-alpha.18",
+ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0-alpha.18.tgz",
+ "integrity": "sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==",
+ "dev": true
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.0-alpha.18",
+ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.0-alpha.18.tgz",
+ "integrity": "sha512-sXh5Y8sqGUkgxpMWUGvRXggxYHAVxg0Pa1C42lQZuPDrW6vHJPR0VCK8Sr7WJsAW530HuNQT/ZIskmXtxjybMQ==",
+ "dev": true,
+ "dependencies": {
+ "@volar/language-core": "2.4.0-alpha.18",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.36.tgz",
+ "integrity": "sha512-qBkndgpwFKdupmOPoiS10i7oFdN7a+4UNDlezD0GlQ1kuA1pNrscg9g12HnB5E8hrWSuEftRsbJhL1HI2zpJhg==",
+ "dependencies": {
+ "@babel/parser": "^7.24.7",
+ "@vue/shared": "3.4.36",
+ "entities": "^5.0.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-core/node_modules/entities": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz",
+ "integrity": "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/@vue/compiler-core/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.36.tgz",
+ "integrity": "sha512-eEIjy4GwwZTFon/Y+WO8tRRNGqylaRlA79T1RLhUpkOzJ7EtZkkb8MurNfkqY6x6Qiu0R7ESspEF7GkPR/4yYg==",
+ "dependencies": {
+ "@vue/compiler-core": "3.4.36",
+ "@vue/shared": "3.4.36"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.36.tgz",
+ "integrity": "sha512-rhuHu7qztt/rNH90dXPTzhB7hLQT2OC4s4GrPVqmzVgPY4XBlfWmcWzn4bIPEWNImt0CjO7kfHAf/1UXOtx3vw==",
+ "dependencies": {
+ "@babel/parser": "^7.24.7",
+ "@vue/compiler-core": "3.4.36",
+ "@vue/compiler-dom": "3.4.36",
+ "@vue/compiler-ssr": "3.4.36",
+ "@vue/shared": "3.4.36",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.10",
+ "postcss": "^8.4.40",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-sfc/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.36.tgz",
+ "integrity": "sha512-Wt1zyheF0zVvRJyhY74uxQbnkXV2Le/JPOrAxooR4rFYKC7cFr+cRqW6RU3cM/bsTy7sdZ83IDuy/gLPSfPGng==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.4.36",
+ "@vue/shared": "3.4.36"
+ }
+ },
+ "node_modules/@vue/compiler-vue2": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+ "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+ "dev": true,
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz",
+ "integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw=="
+ },
+ "node_modules/@vue/language-core": {
+ "version": "2.0.29",
+ "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.29.tgz",
+ "integrity": "sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==",
+ "dev": true,
+ "dependencies": {
+ "@volar/language-core": "~2.4.0-alpha.18",
+ "@vue/compiler-dom": "^3.4.0",
+ "@vue/compiler-vue2": "^2.7.16",
+ "@vue/shared": "^3.4.0",
+ "computeds": "^0.0.1",
+ "minimatch": "^9.0.3",
+ "muggle-string": "^0.4.1",
+ "path-browserify": "^1.0.1"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.36.tgz",
+ "integrity": "sha512-wN1aoCwSoqrt1yt8wO0gc13QaC+Vk1o6AoSt584YHNnz6TGDhh1NCMUYgAnvp4HEIkLdGsaC1bvu/P+wpoDEXw==",
+ "dependencies": {
+ "@vue/shared": "3.4.36"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.36.tgz",
+ "integrity": "sha512-9+TR14LAVEerZWLOm/N/sG2DVYhrH2bKgFrbH/FVt/Q8Jdw4OtdcGMRC6Tx8VAo0DA1eqAqrZaX0fbOaOxxZ4A==",
+ "dependencies": {
+ "@vue/reactivity": "3.4.36",
+ "@vue/shared": "3.4.36"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.36.tgz",
+ "integrity": "sha512-2Qe2fKkLxgZBVvHrG0QMNLL4bsx7Ae88pyXebY2WnQYABpOnGYvA+axMbcF9QwM4yxnsv+aELbC0eiNVns7mGw==",
+ "dependencies": {
+ "@vue/reactivity": "3.4.36",
+ "@vue/runtime-core": "3.4.36",
+ "@vue/shared": "3.4.36",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.36.tgz",
+ "integrity": "sha512-2XW90Rq8+Y7S1EIsAuubZVLm0gCU8HYb5mRAruFdwfC3XSOU5/YKePz29csFzsch8hXaY5UHh7ZMddmi1XTJEA==",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.4.36",
+ "@vue/shared": "3.4.36"
+ },
+ "peerDependencies": {
+ "vue": "3.4.36"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.36.tgz",
+ "integrity": "sha512-fdPLStwl1sDfYuUftBaUVn2pIrVFDASYerZSrlBvVBfylObPA1gtcWJHy5Ox8jLEJ524zBibss488Q3SZtU1uA=="
+ },
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -2525,6 +2715,12 @@
"node": ">=4.0.0"
}
},
+ "node_modules/computeds": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz",
+ "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
+ "dev": true
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2578,8 +2774,7 @@
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
- "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/cypress": {
"version": "13.13.2",
@@ -2766,6 +2961,12 @@
"integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==",
"dev": true
},
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true
+ },
"node_modules/debug": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
@@ -3948,6 +4149,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
+ },
"node_modules/html-encoding-sniffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
@@ -4053,6 +4263,15 @@
"@babel/runtime": "^7.23.2"
}
},
+ "node_modules/i18next-vue": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/i18next-vue/-/i18next-vue-4.0.0.tgz",
+ "integrity": "sha512-yaKWMyFGweyA4EF7JXSGRAvZQ1CJTKjim0iPBsSjFQuuI6lK7cJf6dWK7uO9leB2EnB5JPd8UVtYLTjHXlCVPw==",
+ "peerDependencies": {
+ "i18next": ">=23",
+ "vue": "^3.3.4"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -4825,7 +5044,6 @@
"version": "0.30.11",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
"integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
- "dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
}
@@ -4959,11 +5177,16 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "node_modules/muggle-string": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+ "dev": true
+ },
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -5154,6 +5377,12 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
+ "node_modules/path-browserify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+ "dev": true
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -5257,8 +5486,7 @@
"node_modules/picocolors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
- "dev": true
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -5290,7 +5518,6 @@
"version": "8.4.41",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -5914,7 +6141,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -6270,7 +6496,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
"engines": {
"node": ">=4"
}
@@ -6396,7 +6621,7 @@
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
- "dev": true,
+ "devOptional": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -6789,6 +7014,63 @@
"node": ">=0.10.0"
}
},
+ "node_modules/vscode-uri": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",
+ "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
+ "dev": true
+ },
+ "node_modules/vue": {
+ "version": "3.4.36",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.36.tgz",
+ "integrity": "sha512-mIFvbLgjODfx3Iy1SrxOsiPpDb8Bo3EU+87ioimOZzZTOp15IEdAels70IjBOLO3ZFlLW5AhdwY4dWbXVQKYow==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.4.36",
+ "@vue/compiler-sfc": "3.4.36",
+ "@vue/runtime-dom": "3.4.36",
+ "@vue/server-renderer": "3.4.36",
+ "@vue/shared": "3.4.36"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-router": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.3.tgz",
+ "integrity": "sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/vue-tsc": {
+ "version": "2.0.29",
+ "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.29.tgz",
+ "integrity": "sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==",
+ "dev": true,
+ "dependencies": {
+ "@volar/typescript": "~2.4.0-alpha.18",
+ "@vue/language-core": "2.0.29",
+ "semver": "^7.5.4"
+ },
+ "bin": {
+ "vue-tsc": "bin/vue-tsc.js"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.0"
+ }
+ },
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
diff --git a/package.json b/package.json
index d3dccc5..9247727 100644
--- a/package.json
+++ b/package.json
@@ -4,27 +4,35 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "dev": "vite",
- "component:serve": "NODE_ENV=production vite",
- "build": "tsc && vite build",
+ "react:dev": "vite --config vite-react.config.ts",
+ "react:build": "tsc && vite --config vite-react.config.ts build",
+ "react:component:serve": "NODE_ENV=production vite --config vite-react.config.ts",
+ "vue:dev": "vite --config vite-vue.config.ts",
+ "vue:build": "vue-tsc && vite --config vite-vue.config.ts build",
+ "vue:component:serve": "vite --config vite-vue.config.ts",
+ "preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --ignore-path .gitignore",
"lint:fix": "npm run lint -- --fix",
- "preview": "vite preview",
"test": "vitest",
"test:ci": "vitest run --coverage",
- "test:component": "start-server-and-test component:serve http://localhost:3030 test:component:open",
- "test:component:ci": "start-server-and-test dev http://localhost:3030 test:component:run",
+ "react:test:component": "start-server-and-test react:component:serve http://localhost:3030 test:component:open",
+ "react:test:component:ci": "start-server-and-test vue:component:serve http://localhost:3030 test:component:run",
+ "vue:test:component": "start-server-and-test vue:component:serve http://localhost:3030 test:component:open",
+ "vue:test:component:ci": "start-server-and-test vue:component:serve http://localhost:3030 test:component:run",
"test:component:open": "cypress open --config-file test/component/cypress.config.ts",
"test:component:run": "cypress run --config-file test/component/cypress.config.ts"
},
"dependencies": {
"i18next": "^23.2.11",
"i18next-browser-languagedetector": "^8.0.0",
+ "i18next-vue": "^4.0.0",
"piqure": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.1",
- "react-router-dom": "^6.14.2"
+ "react-router-dom": "^6.14.2",
+ "vue": "^3.4.36",
+ "vue-router": "^4.4.3"
},
"devDependencies": {
"@types/react": "^18.2.17",
@@ -33,6 +41,7 @@
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"@vitejs/plugin-react": "^4.0.1",
+ "@vitejs/plugin-vue": "^5.1.2",
"@vitest/coverage-v8": "^2.0.5",
"axios": "^1.4.0",
"cypress": "^13.13.2",
@@ -45,6 +54,7 @@
"start-server-and-test": "^2.0.0",
"typescript": "^5.0.2",
"vite": "^5.4.0",
- "vitest": "^2.0.5"
+ "vitest": "^2.0.5",
+ "vue-tsc": "^2.0.29"
}
}
diff --git a/src/VueMain.vue b/src/VueMain.vue
new file mode 100644
index 0000000..fb80c6b
--- /dev/null
+++ b/src/VueMain.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/src/library/application/LibraryApp.vue b/src/library/application/LibraryApp.vue
new file mode 100644
index 0000000..a44ab87
--- /dev/null
+++ b/src/library/application/LibraryApp.vue
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/library/application/LibraryProvider.ts b/src/library/application/libraryProvider.ts
similarity index 100%
rename from src/library/application/LibraryProvider.ts
rename to src/library/application/libraryProvider.ts
diff --git a/src/library/application/LibraryRoutes.tsx b/src/library/application/libraryReactRoutes.tsx
similarity index 91%
rename from src/library/application/LibraryRoutes.tsx
rename to src/library/application/libraryReactRoutes.tsx
index 1dbb45d..058cb05 100644
--- a/src/library/application/LibraryRoutes.tsx
+++ b/src/library/application/libraryReactRoutes.tsx
@@ -8,7 +8,7 @@ const BooksPage = () => {
return ;
};
-export const libraryRoutes: RouteObject = {
+export const libraryReactRoutes: RouteObject = {
path: '/',
element: ,
children: [
diff --git a/src/library/application/libraryVueRoutes.ts b/src/library/application/libraryVueRoutes.ts
new file mode 100644
index 0000000..062e517
--- /dev/null
+++ b/src/library/application/libraryVueRoutes.ts
@@ -0,0 +1,17 @@
+import { RouteRecordRaw } from 'vue-router';
+import BookComponent from '@/library/infrastructure/primary/BookComponent.vue';
+import { ISBN } from '@/library/domain/ISBN.ts';
+import LibraryApp from "@/library/application/LibraryApp.vue";
+
+export const libraryVueRoutes =
+ {
+ path: '/',
+ component: LibraryApp,
+ children: [
+ {
+ path: 'book/:isbn',
+ component: BookComponent,
+ props: route => ({ isbn: ISBN.of(route.params['isbn'] as string) }),
+ }
+ ]
+ } satisfies RouteRecordRaw;
diff --git a/src/library/index.tsx b/src/library/index.tsx
deleted file mode 100644
index 3129646..0000000
--- a/src/library/index.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-export { libraryProvider } from './application/LibraryProvider.ts';
-export { libraryRoutes } from './application/LibraryRoutes.tsx';
-
-export { libraryTranslations } from '@/library/application/language/LibraryTranslations.ts';
diff --git a/src/library/infrastructure/primary/BookComponent.vue b/src/library/infrastructure/primary/BookComponent.vue
new file mode 100644
index 0000000..501a576
--- /dev/null
+++ b/src/library/infrastructure/primary/BookComponent.vue
@@ -0,0 +1,52 @@
+
+ {{t('book.inProgress')}}
+ {{ (bookLoader as LoadError).errorMessage }}
+
+
+
+
diff --git a/src/library/infrastructure/primary/BookInfoComponent.vue b/src/library/infrastructure/primary/BookInfoComponent.vue
new file mode 100644
index 0000000..d2e78cc
--- /dev/null
+++ b/src/library/infrastructure/primary/BookInfoComponent.vue
@@ -0,0 +1,29 @@
+
+
+ -
+ {{ `${t('book.title')} ` }}
+ {{ book.title }}
+
+ - {{ book.isbn.get() }}
+
+
+
diff --git a/src/library/infrastructure/primary/Loader.ts b/src/library/infrastructure/primary/Loader.ts
index 3f57c55..165ac0b 100644
--- a/src/library/infrastructure/primary/Loader.ts
+++ b/src/library/infrastructure/primary/Loader.ts
@@ -1,8 +1,8 @@
import { ReactElement } from 'react';
-const LoadingInProgress = Symbol();
-const LoadingError = Symbol();
-const LoadingSuccess = Symbol();
+export const LoadingInProgress = Symbol();
+export const LoadingError = Symbol();
+export const LoadingSuccess = Symbol();
type LoadingStatus = typeof LoadingError | typeof LoadingInProgress | typeof LoadingSuccess;
@@ -10,17 +10,17 @@ interface LoadWithStatus {
status: LoadingStatus;
}
-interface LoadSuccess extends LoadWithStatus {
+export interface LoadSuccess extends LoadWithStatus {
content: T;
status: typeof LoadingSuccess;
}
-interface LoadError extends LoadWithStatus {
+export interface LoadError extends LoadWithStatus {
errorMessage: string;
status: typeof LoadingError;
}
-interface LoadInProgress extends LoadWithStatus {
+export interface LoadInProgress extends LoadWithStatus {
status: typeof LoadingInProgress;
}
diff --git a/src/library/react.tsx b/src/library/react.tsx
new file mode 100644
index 0000000..3d177b2
--- /dev/null
+++ b/src/library/react.tsx
@@ -0,0 +1,4 @@
+export { libraryProvider } from '@/library/application/libraryProvider.ts';
+export { libraryReactRoutes } from '@/library/application/libraryReactRoutes.tsx';
+
+export { libraryTranslations } from '@/library/application/language/LibraryTranslations.ts';
diff --git a/src/library/vue.ts b/src/library/vue.ts
new file mode 100644
index 0000000..adb04b4
--- /dev/null
+++ b/src/library/vue.ts
@@ -0,0 +1,4 @@
+export { libraryProvider } from './application/libraryProvider.ts';
+export { libraryVueRoutes } from './application/libraryVueRoutes.ts';
+
+export { libraryTranslations } from '@/library/application/language/LibraryTranslations.ts';
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..8818587
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,18 @@
+async function createFor(fwk: string): Promise<() => void> {
+ if (fwk === 'vue') {
+ const { createVue } = await import('@/vue.ts');
+ return createVue;
+ }
+ if (fwk === 'react') {
+ const { createReact } = await import('@/react.tsx');
+ return createReact;
+ }
+ throw new Error(`There is no way to create the framework ${fwk}`);
+}
+
+const main = async () => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ await createFor(import.meta.env.VITE_FWK).then(create => create());
+};
+
+void main();
diff --git a/src/main.tsx b/src/main.tsx
deleted file mode 100644
index afa2674..0000000
--- a/src/main.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
-import i18n from 'i18next';
-import { initReactI18next } from 'react-i18next';
-import LanguageDetector from 'i18next-browser-languagedetector';
-import { toTranslationResources } from '@/Translations.ts';
-import { staticRoutes, staticTranslations } from '@/static';
-import { libraryProvider, libraryRoutes, libraryTranslations } from '@/library';
-import { modalProvider, ModalArea } from '@/modal';
-
-const router = createBrowserRouter([libraryRoutes, ...staticRoutes]);
-
-void i18n
- .use(initReactI18next)
- .use(LanguageDetector)
- .init({
- resources: toTranslationResources(staticTranslations, libraryTranslations),
- fallbackLng: 'en',
- interpolation: {
- escapeValue: false,
- },
- });
-
-modalProvider();
-libraryProvider();
-
-ReactDOM.createRoot(document.getElementById('root')!).render(
-
-
-
-
-);
diff --git a/src/modal/ModalAction.ts b/src/modal/ModalAction.ts
index c6a4418..3f433da 100644
--- a/src/modal/ModalAction.ts
+++ b/src/modal/ModalAction.ts
@@ -1,9 +1,7 @@
-import { ReactNode } from 'react';
-
-export class ModalAction {
+export class ModalAction {
constructor(private readonly doc: Document) {}
- open(component: ReactNode) {
+ open(component: C) {
const modalOpen = new CustomEvent('modal.open', { detail: component });
this.doc.dispatchEvent(modalOpen);
}
diff --git a/src/modal/ModalKey.ts b/src/modal/ModalKey.ts
deleted file mode 100644
index 343256d..0000000
--- a/src/modal/ModalKey.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { key } from 'piqure';
-import { ModalAction } from '@/modal/ModalAction.ts';
-import { ModalListen } from '@/modal/ModalListen.ts';
-
-export const MODAL_ACTION = key('Modal action');
-export const MODAL_LISTEN = key('Modal listen');
diff --git a/src/modal/ModalListen.ts b/src/modal/ModalListen.ts
index 50f6425..3de4a53 100644
--- a/src/modal/ModalListen.ts
+++ b/src/modal/ModalListen.ts
@@ -1,11 +1,10 @@
-import { ReactNode } from 'react';
-export class ModalListen {
+export class ModalListen {
constructor(private readonly doc: Document) {}
- onOpen(opened: (component: ReactNode) => void): void {
+ onOpen(opened: (component: T) => void): void {
this.doc.addEventListener('modal.open', event => {
- const custom = event as CustomEvent;
+ const custom = event as CustomEvent;
opened(custom.detail);
});
}
diff --git a/src/modal/ModalProvider.ts b/src/modal/ModalProvider.ts
deleted file mode 100644
index 1d481f8..0000000
--- a/src/modal/ModalProvider.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { provide } from '@/injections.ts';
-import { MODAL_ACTION, MODAL_LISTEN } from '@/modal/ModalKey.ts';
-import { ModalAction } from '@/modal/ModalAction.ts';
-import { ModalListen } from '@/modal/ModalListen.ts';
-
-export const modalProvider = (): void => {
- provide(MODAL_ACTION, new ModalAction(document));
- provide(MODAL_LISTEN, new ModalListen(document));
-};
diff --git a/src/modal/ModalArea.tsx b/src/modal/ReactModalArea.tsx
similarity index 75%
rename from src/modal/ModalArea.tsx
rename to src/modal/ReactModalArea.tsx
index 794f7c8..cfe43a3 100644
--- a/src/modal/ModalArea.tsx
+++ b/src/modal/ReactModalArea.tsx
@@ -1,10 +1,10 @@
import { inject } from '@/injections.ts';
-import { MODAL_ACTION, MODAL_LISTEN } from '@/modal/ModalKey.ts';
+import { REACT_MODAL_ACTION, REACT_MODAL_LISTEN } from '@/modal/ReactModalKey.ts';
import { ReactNode, useEffect, useState } from 'react';
-export const ModalArea = () => {
- const modal = inject(MODAL_LISTEN);
- const modalAction = inject(MODAL_ACTION);
+export const ReactModalArea = () => {
+ const modal = inject(REACT_MODAL_LISTEN);
+ const modalAction = inject(REACT_MODAL_ACTION);
const [body, setBody] = useState();
const [opened, setOpened] = useState(false);
diff --git a/src/modal/ReactModalKey.ts b/src/modal/ReactModalKey.ts
new file mode 100644
index 0000000..cb78a22
--- /dev/null
+++ b/src/modal/ReactModalKey.ts
@@ -0,0 +1,7 @@
+import { key } from 'piqure';
+import { ModalAction } from '@/modal/ModalAction.ts';
+import { ModalListen } from '@/modal/ModalListen.ts';
+import {ReactNode} from "react";
+
+export const REACT_MODAL_ACTION = key>('Modal action');
+export const REACT_MODAL_LISTEN = key>('Modal listen');
diff --git a/src/modal/VueModalArea.vue b/src/modal/VueModalArea.vue
new file mode 100644
index 0000000..70991ac
--- /dev/null
+++ b/src/modal/VueModalArea.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modal/VueModalKey.ts b/src/modal/VueModalKey.ts
new file mode 100644
index 0000000..ddfd854
--- /dev/null
+++ b/src/modal/VueModalKey.ts
@@ -0,0 +1,7 @@
+import { key } from 'piqure';
+import { ModalAction } from '@/modal/ModalAction.ts';
+import { ModalListen } from '@/modal/ModalListen.ts';
+import {Component} from "vue";
+
+export const VUE_MODAL_ACTION = key>('Modal action');
+export const VUE_MODAL_LISTEN = key>('Modal listen');
diff --git a/src/modal/index.ts b/src/modal/index.ts
deleted file mode 100644
index 3e3eb4d..0000000
--- a/src/modal/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export { modalProvider } from './ModalProvider.ts';
-export { ModalArea } from './ModalArea.tsx';
-export { MODAL_ACTION } from '@/modal/ModalKey.ts';
diff --git a/src/modal/react.ts b/src/modal/react.ts
new file mode 100644
index 0000000..7ba28de
--- /dev/null
+++ b/src/modal/react.ts
@@ -0,0 +1,3 @@
+export { reactModalProvider } from './reactModalProvider.ts';
+export { ReactModalArea } from './ReactModalArea.tsx';
+export { REACT_MODAL_ACTION } from '@/modal/ReactModalKey.ts';
diff --git a/src/modal/reactModalProvider.ts b/src/modal/reactModalProvider.ts
new file mode 100644
index 0000000..ddc177a
--- /dev/null
+++ b/src/modal/reactModalProvider.ts
@@ -0,0 +1,9 @@
+import { provide } from '@/injections.ts';
+import { REACT_MODAL_ACTION, REACT_MODAL_LISTEN } from '@/modal/ReactModalKey.ts';
+import { ModalAction } from '@/modal/ModalAction.ts';
+import { ModalListen } from '@/modal/ModalListen.ts';
+
+export const reactModalProvider = (): void => {
+ provide(REACT_MODAL_ACTION, new ModalAction(document));
+ provide(REACT_MODAL_LISTEN, new ModalListen(document));
+};
diff --git a/src/modal/vue.ts b/src/modal/vue.ts
new file mode 100644
index 0000000..cfa05fc
--- /dev/null
+++ b/src/modal/vue.ts
@@ -0,0 +1,6 @@
+export { vueModalProvider } from './vueModalProvider.ts';
+
+import VueModalArea from "@/modal/VueModalArea.vue";
+export { VueModalArea };
+
+export { VUE_MODAL_ACTION } from '@/modal/VueModalKey.ts';
diff --git a/src/modal/vueModalProvider.ts b/src/modal/vueModalProvider.ts
new file mode 100644
index 0000000..4a6eb4d
--- /dev/null
+++ b/src/modal/vueModalProvider.ts
@@ -0,0 +1,10 @@
+import { provide } from '@/injections.ts';
+import { ModalAction } from '@/modal/ModalAction.ts';
+import { ModalListen } from '@/modal/ModalListen.ts';
+import {VUE_MODAL_ACTION} from "@/modal/vue.ts";
+import {VUE_MODAL_LISTEN} from "@/modal/VueModalKey.ts";
+
+export const vueModalProvider = (): void => {
+ provide(VUE_MODAL_ACTION, new ModalAction(document));
+ provide(VUE_MODAL_LISTEN, new ModalListen(document));
+};
diff --git a/src/react.tsx b/src/react.tsx
new file mode 100644
index 0000000..23cd4bf
--- /dev/null
+++ b/src/react.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import LanguageDetector from 'i18next-browser-languagedetector';
+import { toTranslationResources } from '@/Translations.ts';
+import { staticReactRoutes, staticTranslations } from '@/static/react';
+import { libraryProvider, libraryReactRoutes, libraryTranslations } from '@/library/react.tsx';
+import { reactModalProvider, ReactModalArea } from '@/modal/react';
+
+export const createReact = () => {
+ const router = createBrowserRouter([libraryReactRoutes, ...staticReactRoutes]);
+
+ void i18n
+ .use(initReactI18next)
+ .use(LanguageDetector)
+ .init({
+ resources: toTranslationResources(staticTranslations, libraryTranslations),
+ fallbackLng: 'en',
+ interpolation: {
+ escapeValue: false,
+ },
+ });
+
+ reactModalProvider();
+ libraryProvider();
+
+ ReactDOM.createRoot(document.getElementById('app')!).render(
+
+
+
+
+ );
+};
diff --git a/src/static/ContactComponent.vue b/src/static/ContactComponent.vue
new file mode 100644
index 0000000..543448a
--- /dev/null
+++ b/src/static/ContactComponent.vue
@@ -0,0 +1,10 @@
+
+ {{t('contact.title')}}
+ {{t('contact.email')}}
+
+
+
diff --git a/src/static/about/About.tsx b/src/static/about/About.tsx
index 85566a8..34d340a 100644
--- a/src/static/about/About.tsx
+++ b/src/static/about/About.tsx
@@ -1,13 +1,13 @@
import { useTranslation } from 'react-i18next';
import { inject } from '@/injections.ts';
-import { MODAL_ACTION } from '@/modal';
+import { REACT_MODAL_ACTION } from '@/modal/react';
import { MoreInfo } from '@/static/about/MoreInfo.tsx';
import { CGU } from '@/static/about/CGU.tsx';
export const About = () => {
const { t } = useTranslation();
- const modal = inject(MODAL_ACTION);
+ const modal = inject(REACT_MODAL_ACTION);
const moreInfo = () => {
modal.open();
diff --git a/src/static/about/AboutComponent.vue b/src/static/about/AboutComponent.vue
new file mode 100644
index 0000000..49b7ff5
--- /dev/null
+++ b/src/static/about/AboutComponent.vue
@@ -0,0 +1,40 @@
+
+ {{t('about.title')}}
+ {{t('about.description')}}
+
+
+
+
+
diff --git a/src/static/about/CGUComponent.vue b/src/static/about/CGUComponent.vue
new file mode 100644
index 0000000..a84d6b3
--- /dev/null
+++ b/src/static/about/CGUComponent.vue
@@ -0,0 +1,9 @@
+
+ {{t('about.cgu.title')}}
+
+
+
diff --git a/src/static/about/MoreInfoComponent.vue b/src/static/about/MoreInfoComponent.vue
new file mode 100644
index 0000000..7b8c89c
--- /dev/null
+++ b/src/static/about/MoreInfoComponent.vue
@@ -0,0 +1,9 @@
+
+ {{t('about.more-info.title')}}
+
+
+
diff --git a/src/static/index.ts b/src/static/index.ts
deleted file mode 100644
index a4ac588..0000000
--- a/src/static/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { staticRoutes } from './StaticRoutes.tsx';
-export { staticTranslations } from './language/StaticTranslations.ts';
diff --git a/src/static/language/StaticTranslations.ts b/src/static/language/staticTranslations.ts
similarity index 100%
rename from src/static/language/StaticTranslations.ts
rename to src/static/language/staticTranslations.ts
diff --git a/src/static/react.ts b/src/static/react.ts
new file mode 100644
index 0000000..445e0b6
--- /dev/null
+++ b/src/static/react.ts
@@ -0,0 +1,2 @@
+export { staticReactRoutes } from './staticReactRoutes.tsx';
+export { staticTranslations } from './language/staticTranslations.ts';
diff --git a/src/static/StaticRoutes.tsx b/src/static/staticReactRoutes.tsx
similarity index 83%
rename from src/static/StaticRoutes.tsx
rename to src/static/staticReactRoutes.tsx
index 83e1745..9d7ff19 100644
--- a/src/static/StaticRoutes.tsx
+++ b/src/static/staticReactRoutes.tsx
@@ -2,7 +2,7 @@ import { RouteObject } from 'react-router-dom';
import { About } from '@/static/about/About.tsx';
import { Contact } from '@/static/Contact.tsx';
-export const staticRoutes: RouteObject[] = [
+export const staticReactRoutes: RouteObject[] = [
{
path: '/about',
element: ,
diff --git a/src/static/staticVueRoutes.ts b/src/static/staticVueRoutes.ts
new file mode 100644
index 0000000..d7c8080
--- /dev/null
+++ b/src/static/staticVueRoutes.ts
@@ -0,0 +1,14 @@
+import {RouteRecordRaw} from "vue-router";
+import ContactComponent from "@/static/ContactComponent.vue";
+import AboutComponent from "@/static/about/AboutComponent.vue";
+
+export const staticVueRoutes = [
+ {
+ path: '/about',
+ component: AboutComponent,
+ },
+ {
+ path: '/contact',
+ component: ContactComponent,
+ }
+] satisfies RouteRecordRaw[];
diff --git a/src/static/vue.ts b/src/static/vue.ts
new file mode 100644
index 0000000..c4e1094
--- /dev/null
+++ b/src/static/vue.ts
@@ -0,0 +1,2 @@
+export { staticVueRoutes } from './staticVueRoutes.ts';
+export { staticTranslations } from './language/staticTranslations.ts';
diff --git a/src/vue.ts b/src/vue.ts
new file mode 100644
index 0000000..4de48e9
--- /dev/null
+++ b/src/vue.ts
@@ -0,0 +1,30 @@
+import { createApp } from 'vue';
+import VueMain from './VueMain.vue';
+import {libraryProvider, libraryTranslations, libraryVueRoutes} from '@/library/vue';
+import { createRouter, createWebHistory } from 'vue-router';
+import i18next from 'i18next';
+import I18NextVue from 'i18next-vue';
+import { toTranslationResources } from '@/Translations.ts';
+import LanguageDetector from 'i18next-browser-languagedetector';
+import {staticTranslations, staticVueRoutes} from "@/static/vue.ts";
+import {vueModalProvider} from "@/modal/vue.ts";
+
+export const createVue = () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [libraryVueRoutes, ...staticVueRoutes],
+ });
+
+ void i18next.use(LanguageDetector).init({
+ resources: toTranslationResources(staticTranslations, libraryTranslations),
+ fallbackLng: 'en',
+ interpolation: {
+ escapeValue: false,
+ },
+ });
+
+ vueModalProvider();
+ libraryProvider();
+
+ createApp(VueMain).use(router).use(I18NextVue, { i18next }).mount('#app');
+};
diff --git a/test/component/spec/library/library.spec.ts b/test/component/spec/library/library.spec.ts
index ea69a7a..e451f27 100644
--- a/test/component/spec/library/library.spec.ts
+++ b/test/component/spec/library/library.spec.ts
@@ -80,7 +80,7 @@ describe('Library', () => {
cy.contains(dataSelector('book.label.title'), 'Title: ');
});
- it.only('Should have french labels', () => {
+ it('Should have french labels', () => {
stubOpenLibraryIsbn();
cy.visit('/book/9780321125217', loadLanguage('fr'));
diff --git a/tsconfig.app.json b/tsconfig.app.json
new file mode 100644
index 0000000..938a7db
--- /dev/null
+++ b/tsconfig.app.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "preserve",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/tsconfig.json b/tsconfig.json
index 2a27e96..1ffef60 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,24 +1,7 @@
{
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "react-jsx",
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
- "paths": {
- "@/*": ["./src/*"]
- }
- },
- "include": ["src"],
- "references": [{ "path": "./tsconfig.node.json" }]
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
}
diff --git a/tsconfig.lint.json b/tsconfig.lint.json
deleted file mode 100644
index d5c782d..0000000
--- a/tsconfig.lint.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "include": ["*.ts", "src", "test"]
-}
diff --git a/tsconfig.node.json b/tsconfig.node.json
index 42872c5..3e00f47 100644
--- a/tsconfig.node.json
+++ b/tsconfig.node.json
@@ -1,10 +1,22 @@
{
"compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
+ "target": "ES2022",
+ "lib": ["ES2023"],
"module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
"moduleResolution": "bundler",
- "allowSyntheticDefaultImports": true
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
},
- "include": ["vite.config.ts"]
+ "include": ["vite-vue.config.ts"]
}
diff --git a/vite.config.ts b/vite-react.config.ts
similarity index 70%
rename from vite.config.ts
rename to vite-react.config.ts
index b5c6959..55d2b78 100644
--- a/vite.config.ts
+++ b/vite-react.config.ts
@@ -11,4 +11,10 @@ export default defineConfig({
server: {
port: 3030,
},
+ envDir: path.resolve(__dirname, 'config', 'react'),
+ build: {
+ rollupOptions: {
+ external: [new RegExp(/\.vue/)],
+ },
+ },
});
diff --git a/vite-vue.config.ts b/vite-vue.config.ts
new file mode 100644
index 0000000..706d5ac
--- /dev/null
+++ b/vite-vue.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import * as path from 'path';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [vue()],
+ resolve: {
+ alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
+ },
+ server: {
+ port: 3030,
+ },
+ envDir: path.resolve(__dirname, 'config', 'vue'),
+});