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