Initial boilerplate

This commit is contained in:
Kujiu 2021-11-29 01:06:34 +01:00
parent cd4ae7b106
commit afdf032ab2
Signed by: kujiu
GPG key ID: ABBB2CAC6855599F
28 changed files with 6958 additions and 0 deletions

3
.babelrc Normal file
View file

@ -0,0 +1,3 @@
{
"plugins": ["istanbul"]
}

3
.gitignore vendored
View file

@ -148,3 +148,6 @@ dist
.yarn/install-state.gz .yarn/install-state.gz
.pnp.* .pnp.*
#cypress
cypress/videos
cypress/screenshots

View file

@ -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. 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
View file

@ -0,0 +1,4 @@
{
"coverageFolder": "coverage",
"baseUrl": "http://localhost:3000"
}

View 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
View 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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/icon-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/icon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

30
src/NervTN.vue Normal file
View 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
View 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

View file

@ -0,0 +1,2 @@
<template>
</template>

View file

@ -0,0 +1,7 @@
<template>
<h1>Communication</h1>
<h1>Accounting</h1>
<h1>Ordering</h1>
<h1>Stocks</h1>
<h1>Monitoring</h1>
</template>

View 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"/>

View file

@ -0,0 +1,2 @@
/* jshint -W097 */ // don't warn about "use strict"
"use strict";

11
src/locale/en.json Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,2 @@
/* jshint -W097 */ // don't warn about "use strict"
"use strict";

6463
yarn.lock Normal file

File diff suppressed because it is too large Load diff