Initial boilerplate
This commit is contained in:
parent
cd4ae7b106
commit
afdf032ab2
28 changed files with 6958 additions and 0 deletions
3
.babelrc
Normal file
3
.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"plugins": ["istanbul"]
|
||||
}
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -148,3 +148,6 @@ dist
|
|||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
#cypress
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
|
|
|
@ -2,3 +2,11 @@ Nerv Tales Network Web Client
|
|||
#############################
|
||||
|
||||
XMPP web client, authoring tool, library, accessibility, adaptation, copyright exemption, risk, pdca, documents and accounting management system.
|
||||
|
||||
.. important::
|
||||
|
||||
When deploying, configure your webserver to:
|
||||
|
||||
- serve manifest.webmanifest with mimetype application/manifest+json;
|
||||
- serve .mjs files as application/javascript;
|
||||
- serve in https and redirect http to https.
|
||||
|
|
4
cypress.json
Normal file
4
cypress.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"coverageFolder": "coverage",
|
||||
"baseUrl": "http://localhost:3000"
|
||||
}
|
10
cypress/integration/a11y/main.spec.js
Normal file
10
cypress/integration/a11y/main.spec.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
describe('Main accessibility', () => {
|
||||
it('a11y check', () => {
|
||||
cy.visit('index.html');
|
||||
cy.injectAxe();
|
||||
cy.checkA11y();
|
||||
});
|
||||
});
|
16
cypress/plugins/index.js
Normal file
16
cypress/plugins/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
const {startDevServer} = require('@cypress/vite-dev-server');
|
||||
|
||||
module.exports = (on, config) => {
|
||||
require('@cypress/code-coverage/task')(on, config);
|
||||
on('file:preprocessor', require('@cypress/code-coverage/use-babelrc'));
|
||||
on('dev-server:start', (options) => {
|
||||
return startDevServer({
|
||||
options,
|
||||
webpackConfig
|
||||
});
|
||||
});
|
||||
return config;
|
||||
};
|
5
cypress/support/index.js
Normal file
5
cypress/support/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
import 'cypress-axe';
|
||||
import '@cypress/code-coverage/support';
|
13
index.html
Normal file
13
index.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nerv Tales Network</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
35
package.json
Normal file
35
package.json
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "nervtn-web",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"cypress:open": "./node_modules/.bin/cypress open",
|
||||
"cypress:run": "./node_modules/.bin/cypress run",
|
||||
"test:ci": "./node_modules/.bin/cypress run",
|
||||
"test:record": "./node_modules/.bin/cypress run --record",
|
||||
"test:coverage-report": "./node_modules/.bin/nyc report --reporter=text-summary"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.16",
|
||||
"vue-i18n": "9",
|
||||
"vue-router": "4",
|
||||
"vuex": "4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/code-coverage": "^3.9.11",
|
||||
"@cypress/vite-dev-server": "^2.2.1",
|
||||
"@intlify/vite-plugin-vue-i18n": "3",
|
||||
"@vitejs/plugin-vue": "^1.9.3",
|
||||
"axe-core": "^4.3.5",
|
||||
"babel-plugin-istanbul": "^6.1.1",
|
||||
"cypress": "^9.1.0",
|
||||
"cypress-axe": "^0.13.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"less": "^4.1.2",
|
||||
"vite": "^2.6.4",
|
||||
"vite-plugin-pwa": "^0.11.8",
|
||||
"workbox-precaching": "^6.4.1"
|
||||
}
|
||||
}
|
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
BIN
public/icon-192.png
Normal file
BIN
public/icon-192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
public/icon-512.png
Normal file
BIN
public/icon-512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
30
src/NervTN.vue
Normal file
30
src/NervTN.vue
Normal file
|
@ -0,0 +1,30 @@
|
|||
<script setup>
|
||||
import ReloadPWA from './components/ReloadPWA.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ReloadPWA/>
|
||||
<main>
|
||||
<router-view></router-view>
|
||||
</main>
|
||||
<header>
|
||||
<router-link to='/apps'>
|
||||
<img alt="" src="./assets/logo.svg"/>
|
||||
{{ $t('home.apps') }}
|
||||
</router-link>
|
||||
</header>
|
||||
<footer>
|
||||
</footer>
|
||||
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
#app {
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<i18n lang="json" locale="en" src="./locale/en.json"/>
|
||||
<i18n lang="json" locale="fr" src="./locale/fr.json"/>
|
147
src/assets/logo.svg
Normal file
147
src/assets/logo.svg
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="144"
|
||||
height="144"
|
||||
viewBox="0 0 38.099999 38.100001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="Nerv-onLight.svg"
|
||||
inkscape:export-filename="Nerv-onLight.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient1557"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop1553"
|
||||
offset="0"
|
||||
style="stop-color:#729fcf;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop1555"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient944">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop940" />
|
||||
<stop
|
||||
style="stop-color:#fcaf3e;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop942" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1557"
|
||||
id="linearGradient946"
|
||||
x1="66"
|
||||
y1="40.00005"
|
||||
x2="66"
|
||||
y2="136.00005"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.22678572,0,0,0.22678572,2.4190668,265.55236)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1557"
|
||||
id="linearGradient1638"
|
||||
x1="59.266666"
|
||||
y1="275.83331"
|
||||
x2="59.266666"
|
||||
y2="299.11667"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-41.539586,-8.4784701)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient944"
|
||||
id="linearGradient1646"
|
||||
x1="59.266666"
|
||||
y1="265.25"
|
||||
x2="59.266666"
|
||||
y2="288.53333"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-38.893751,-0.0118033)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#808080"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4"
|
||||
inkscape:cx="-72.206246"
|
||||
inkscape:cy="-20.326477"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1884"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid815"
|
||||
empspacing="4" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:date>2019</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Timothée Giet</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<cc:license
|
||||
rdf:resource="" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-258.89999)">
|
||||
<circle
|
||||
style="opacity:1;vector-effect:none;fill:#292929;fill-opacity:1;stroke:none;stroke-width:1.28157544;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path817-2-9"
|
||||
cx="19.049999"
|
||||
cy="277.93817"
|
||||
r="16.404167" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:url(#linearGradient1646);fill-opacity:1;stroke:none;stroke-width:1.32291687;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 24.60625,270.21413 v 18.30741 l -8.466667,-12.7 v 18.30741 c 1.358674,0.48624 2.790281,0.76099 4.233333,0.76621 7.014016,0 12.7,-5.7096 12.700001,-12.72362 -0.0069,-5.37607 -3.398051,-10.16539 -8.466667,-11.95741 z"
|
||||
id="path1612"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:url(#linearGradient1638);fill-opacity:1;stroke:none;stroke-width:1.32291687;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 13.493748,285.66223 v -18.30741 l 8.466667,12.7 v -18.30741 a 12.700001,12.700001 0 0 0 -4.233334,-0.74259 12.700001,12.700001 0 0 0 -12.6999987,12.7 12.700001,12.700001 0 0 0 8.4666657,11.95741 z"
|
||||
id="path1612-1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.1 KiB |
2
src/components/Dashboard.vue
Normal file
2
src/components/Dashboard.vue
Normal file
|
@ -0,0 +1,2 @@
|
|||
<template>
|
||||
</template>
|
7
src/components/NervTNApps.vue
Normal file
7
src/components/NervTNApps.vue
Normal file
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h1>Communication</h1>
|
||||
<h1>Accounting</h1>
|
||||
<h1>Ordering</h1>
|
||||
<h1>Stocks</h1>
|
||||
<h1>Monitoring</h1>
|
||||
</template>
|
50
src/components/ReloadPWA.vue
Normal file
50
src/components/ReloadPWA.vue
Normal file
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<div v-if="offlineReady || needRefresh" role="alert">
|
||||
<div class="admonition warning">
|
||||
<span v-if="offlineReady">
|
||||
{{ $t('pwa.ready') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('pwa.new_content') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="">
|
||||
<button v-if="needRefresh" @click="updateServiceWorker()">
|
||||
{{ $t('pwa.reload') }}
|
||||
</button>
|
||||
<button @click="close">
|
||||
{{ $t('pwa.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {defineComponent} from "vue";
|
||||
import {useRegisterSW} from "virtual:pwa-register/vue";
|
||||
|
||||
const {updateServiceWorker} = useRegisterSW();
|
||||
|
||||
export default defineComponent({
|
||||
name: "ReloadPWA",
|
||||
setup() {
|
||||
const {offlineReady, needRefresh, updateServiceWorker} = useRegisterSW();
|
||||
const close = async () => {
|
||||
offlineReady.value = false;
|
||||
needRefresh.value = false;
|
||||
};
|
||||
return {offlineReady, needRefresh, updateServiceWorker, close};
|
||||
},
|
||||
methods: {
|
||||
async close() {
|
||||
this.offlineReady.value = false;
|
||||
this.needRefresh.value = false;
|
||||
},
|
||||
async updateServiceWorker() {
|
||||
await updateServiceWorker();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<i18n lang="json" locale="en" src="../locale/en.json"/>
|
||||
<i18n lang="json" locale="fr" src="../locale/fr.json"/>
|
2
src/components/xmpp/xmpp.js
Normal file
2
src/components/xmpp/xmpp.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
11
src/locale/en.json
Normal file
11
src/locale/en.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"home": {
|
||||
"apps": "Applications"
|
||||
},
|
||||
"pwa": {
|
||||
"ready": "Your applications are ready for offline.",
|
||||
"new_content": "New version available!",
|
||||
"later": "See later",
|
||||
"reload": "Reload app"
|
||||
}
|
||||
}
|
11
src/locale/fr.json
Normal file
11
src/locale/fr.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"home": {
|
||||
"apps": "Applications"
|
||||
},
|
||||
"pwa": {
|
||||
"ready": "Vous êtes prêts pour le mode hors-ligne.",
|
||||
"new_content": "Nouvelle version disponible !",
|
||||
"later": "Plus tard",
|
||||
"reload": "Recharger"
|
||||
}
|
||||
}
|
30
src/main.js
Normal file
30
src/main.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
import {createApp} from 'vue';
|
||||
import {createI18n} from 'vue-i18n';
|
||||
import App from './NervTN.vue';
|
||||
import store from './nervtn-state';
|
||||
import router from './nervtn-routes';
|
||||
|
||||
var languages = navigator.languages;
|
||||
if(languages===undefined||languages.length<1) {
|
||||
languages = [navigator.language];
|
||||
}
|
||||
|
||||
if(!languages[0]) {
|
||||
languages = ['en'];
|
||||
}
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(createI18n({
|
||||
locale: languages[0].trim().split(/-|_/)[0],
|
||||
fallbackLocale: 'en',
|
||||
legacy: false,
|
||||
globalInjection: true,
|
||||
messages: {}
|
||||
}));
|
||||
app.use(router);
|
||||
app.use(store);
|
||||
app.mount('#app');
|
19
src/nervtn-routes.js
Normal file
19
src/nervtn-routes.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
import * as VueRouter from 'vue-router';
|
||||
|
||||
const Apps = () => import('./components/NervTNApps.vue');
|
||||
const Dashboard = () => import('./components/Dashboard.vue');
|
||||
|
||||
const routes = [
|
||||
{path: '/', component: Dashboard},
|
||||
{path: '/apps', component: Apps}
|
||||
];
|
||||
|
||||
const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHashHistory(),
|
||||
routes
|
||||
});
|
||||
|
||||
export default router;
|
13
src/nervtn-state.js
Normal file
13
src/nervtn-state.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
import Vuex from 'vuex';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
modules: {}
|
||||
});
|
||||
|
||||
export default store;
|
12
src/sw.js
Normal file
12
src/sw.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
import {precacheAndRoute} from 'workbox-precaching';
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
if(event.data && event.data.type === 'SKIP_WAITING') {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
62
vite.config.js
Normal file
62
vite.config.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
||||
|
||||
import path from 'path';
|
||||
import {defineConfig} from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueI18n from '@intlify/vite-plugin-vue-i18n';
|
||||
import {VitePWA} from 'vite-plugin-pwa';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
sourcemap: true,
|
||||
manifest: true
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
vueI18n({
|
||||
include: path.resolve(__dirname, '**/locale/**')
|
||||
}),
|
||||
VitePWA({
|
||||
mode: "production",
|
||||
base: "/",
|
||||
srcDir: "src",
|
||||
filename: "sw.js",
|
||||
includeAssets: [
|
||||
"/favicon.png"
|
||||
],
|
||||
strategies: "injectManifest",
|
||||
workbox: {
|
||||
sourcemap: true
|
||||
},
|
||||
manifest: {
|
||||
name: "Nerv Tales Network",
|
||||
short_name: "NervTN",
|
||||
start_url: "/",
|
||||
display: "standalone",
|
||||
icons: [
|
||||
{
|
||||
src: "icon-192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "icon-512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "apple-touch-icon.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
],
|
||||
server: {
|
||||
strictPort: true,
|
||||
force: true
|
||||
}
|
||||
});
|
2
vue.config.js
Normal file
2
vue.config.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
/* jshint -W097 */ // don't warn about "use strict"
|
||||
"use strict";
|
Loading…
Reference in a new issue