crazy
This commit is contained in:
146
api/package-lock.json
generated
146
api/package-lock.json
generated
@@ -1272,6 +1272,11 @@
|
|||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"append-field": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY="
|
||||||
|
},
|
||||||
"argparse": {
|
"argparse": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||||
@@ -1687,6 +1692,38 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||||
},
|
},
|
||||||
|
"busboy": {
|
||||||
|
"version": "0.2.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
||||||
|
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
|
||||||
|
"requires": {
|
||||||
|
"dicer": "0.2.5",
|
||||||
|
"readable-stream": "1.1.x"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "1.1.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||||
|
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.1",
|
||||||
|
"isarray": "0.0.1",
|
||||||
|
"string_decoder": "~0.10.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "0.10.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||||
|
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"bytes": {
|
"bytes": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||||
@@ -1996,6 +2033,46 @@
|
|||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
},
|
},
|
||||||
|
"concat-stream": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||||
|
"requires": {
|
||||||
|
"buffer-from": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^2.2.2",
|
||||||
|
"typedarray": "^0.0.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"configstore": {
|
"configstore": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
|
||||||
@@ -2309,6 +2386,38 @@
|
|||||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||||
},
|
},
|
||||||
|
"dicer": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
||||||
|
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
|
||||||
|
"requires": {
|
||||||
|
"readable-stream": "1.1.x",
|
||||||
|
"streamsearch": "0.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "1.1.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||||
|
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.1",
|
||||||
|
"isarray": "0.0.1",
|
||||||
|
"string_decoder": "~0.10.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "0.10.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||||
|
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dns-prefetch-control": {
|
"dns-prefetch-control": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
|
||||||
@@ -4604,7 +4713,6 @@
|
|||||||
"version": "0.5.5",
|
"version": "0.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
@@ -4619,6 +4727,21 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
|
"multer": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==",
|
||||||
|
"requires": {
|
||||||
|
"append-field": "^1.0.0",
|
||||||
|
"busboy": "^0.2.11",
|
||||||
|
"concat-stream": "^1.5.2",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"on-finished": "^2.3.0",
|
||||||
|
"type-is": "^1.6.4",
|
||||||
|
"xtend": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mute-stream": {
|
"mute-stream": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||||
@@ -4758,8 +4881,7 @@
|
|||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"object-copy": {
|
"object-copy": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -5163,8 +5285,7 @@
|
|||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"progress": {
|
"progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
@@ -6101,6 +6222,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||||
},
|
},
|
||||||
|
"streamsearch": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||||
|
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||||
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||||
@@ -6443,6 +6569,11 @@
|
|||||||
"mime-types": "~2.1.24"
|
"mime-types": "~2.1.24"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"typedarray": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||||
|
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||||
|
},
|
||||||
"typedarray-to-buffer": {
|
"typedarray-to-buffer": {
|
||||||
"version": "3.1.5",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||||
@@ -6878,6 +7009,11 @@
|
|||||||
"@babel/runtime-corejs3": "^7.8.3"
|
"@babel/runtime-corejs3": "^7.8.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"xtend": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||||
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"@babel/node": "7.8.7",
|
"@babel/node": "7.8.7",
|
||||||
"@babel/plugin-proposal-class-properties": "7.8.3",
|
"@babel/plugin-proposal-class-properties": "7.8.3",
|
||||||
"@babel/preset-env": "7.9.6",
|
"@babel/preset-env": "7.9.6",
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
"cacheman": "2.2.1",
|
"cacheman": "2.2.1",
|
||||||
"cacheman-file": "0.2.1",
|
"cacheman-file": "0.2.1",
|
||||||
"compression": "1.7.4",
|
"compression": "1.7.4",
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
"form-data": "3.0.0",
|
"form-data": "3.0.0",
|
||||||
"helmet": "3.22.0",
|
"helmet": "3.22.0",
|
||||||
"jsdom": "16.2.2",
|
"jsdom": "16.2.2",
|
||||||
|
"multer": "^1.4.2",
|
||||||
"node-fetch": "2.6.0",
|
"node-fetch": "2.6.0",
|
||||||
"puppeteer": "3.1.0"
|
"puppeteer": "3.1.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ class PlateRecognizr {
|
|||||||
|
|
||||||
fetch(image) {
|
fetch(image) {
|
||||||
const body = new FormData();
|
const body = new FormData();
|
||||||
body.append('upload', fs.createReadStream('test.jpg'));
|
body.append('upload', image);
|
||||||
body.append('regions', 'gb'); // Change to your country
|
body.append('regions', 'ee'); // Change to your country
|
||||||
return fetch(ALPR_API_PATH, {
|
return fetch(ALPR_API_PATH, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -2,21 +2,34 @@ import express from 'express';
|
|||||||
import http from 'http';
|
import http from 'http';
|
||||||
import compression from 'compression';
|
import compression from 'compression';
|
||||||
import helmet from 'helmet';
|
import helmet from 'helmet';
|
||||||
|
import multer from 'multer';
|
||||||
|
import bodyParser from 'body-parser';
|
||||||
import Hack from '../components/Hack';
|
import Hack from '../components/Hack';
|
||||||
|
import PlateRecognizr from '../api/PlateRecognizr';
|
||||||
|
|
||||||
const PORT = process.env.PORT || "8000";
|
const PORT = process.env.PORT || '8000';
|
||||||
|
const upload = multer({ dest: '/tmp' });
|
||||||
|
|
||||||
class BasicApi {
|
class BasicApi {
|
||||||
app;
|
app;
|
||||||
server;
|
server;
|
||||||
hack;
|
hack;
|
||||||
|
alpr;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.app = express();
|
this.app = express();
|
||||||
|
this.app.use(express.static('public'));
|
||||||
|
this.app.use(bodyParser.urlencoded({ extended: false }));
|
||||||
this.app.use(compression());
|
this.app.use(compression());
|
||||||
this.app.use(helmet());
|
this.app.use(helmet());
|
||||||
|
this.app.use((req, res, next) => {
|
||||||
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
|
||||||
|
next();
|
||||||
|
});
|
||||||
this.server = http.createServer(this.app);
|
this.server = http.createServer(this.app);
|
||||||
this.hack = new Hack();
|
this.hack = new Hack();
|
||||||
|
this.alpr = new PlateRecognizr();
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@@ -34,6 +47,14 @@ class BasicApi {
|
|||||||
.status(200)
|
.status(200)
|
||||||
.send(this.hack.getCar());
|
.send(this.hack.getCar());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.app.post('/alpr', upload.single('upload'), async ({ body }, response) => {
|
||||||
|
const { upload: image } = body;
|
||||||
|
console.log(Object.keys(body));
|
||||||
|
const plate = await (await this.alpr.fetch(image)).json();
|
||||||
|
console.log(plate);
|
||||||
|
response.status(200).json(plate);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ module.exports = (api) => {
|
|||||||
'@context': './src/context',
|
'@context': './src/context',
|
||||||
'@components': './src/components',
|
'@components': './src/components',
|
||||||
'@hook': './src/hook',
|
'@hook': './src/hook',
|
||||||
|
'@actions': './src/actions',
|
||||||
'@assets': './assets',
|
'@assets': './assets',
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|||||||
@@ -125,5 +125,6 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'no-console': 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
BIN
frontend/assets/images/Maanteeamet.png
Normal file
BIN
frontend/assets/images/Maanteeamet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
11
frontend/package-lock.json
generated
11
frontend/package-lock.json
generated
@@ -1175,6 +1175,11 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@fortawesome/fontawesome-free": {
|
||||||
|
"version": "5.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz",
|
||||||
|
"integrity": "sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg=="
|
||||||
|
},
|
||||||
"@nodelib/fs.scandir": {
|
"@nodelib/fs.scandir": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
|
||||||
@@ -4356,6 +4361,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dotenv": {
|
||||||
|
"version": "8.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||||
|
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"duplexer": {
|
"duplexer": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "Base React template",
|
"description": "Base React template",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "nodemon --exec \"cross-env NODE_ENV=development webpack-dev-server\"",
|
"start": "nodemon --exec \"cross-env NODE_ENV=development webpack-dev-server -r dotenv/config \"",
|
||||||
"prebundle": "rimraf build/*",
|
"prebundle": "rimraf build/*",
|
||||||
"bundle": "cross-env NODE_ENV=production webpack",
|
"bundle": "cross-env NODE_ENV=production webpack",
|
||||||
"cacheclean": "rimraf node_modules/.cache/hard-source",
|
"cacheclean": "rimraf node_modules/.cache/hard-source",
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-free": "5.13.0",
|
||||||
"@reduxjs/toolkit": "1.3.6",
|
"@reduxjs/toolkit": "1.3.6",
|
||||||
"core-js": "3.6.5",
|
"core-js": "3.6.5",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
@@ -56,6 +57,7 @@
|
|||||||
"copy-webpack-plugin": "6.0.1",
|
"copy-webpack-plugin": "6.0.1",
|
||||||
"cross-env": "7.0.2",
|
"cross-env": "7.0.2",
|
||||||
"css-loader": "3.5.3",
|
"css-loader": "3.5.3",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
"eslint": "7.1.0",
|
"eslint": "7.1.0",
|
||||||
"eslint-config-airbnb": "18.1.0",
|
"eslint-config-airbnb": "18.1.0",
|
||||||
"eslint-import-resolver-babel-module": "5.1.2",
|
"eslint-import-resolver-babel-module": "5.1.2",
|
||||||
|
|||||||
2
frontend/public/assets/css/skeleton.min.css
vendored
2
frontend/public/assets/css/skeleton.min.css
vendored
File diff suppressed because one or more lines are too long
21
frontend/src/actions/CaptureActions.js
Normal file
21
frontend/src/actions/CaptureActions.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
const API_BASE_PATH = process.env.NODE_ENV === 'production'
|
||||||
|
? process.env.API_BASE_PATH
|
||||||
|
: 'http://localhost:4000';
|
||||||
|
|
||||||
|
export const getPlateRecognized = async (image) => {
|
||||||
|
const body = new FormData();
|
||||||
|
body.append('upload', image);
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_PATH}/alpr`, {
|
||||||
|
method: 'POST',
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
console.log(response);
|
||||||
|
const data = await response.json();
|
||||||
|
console.log(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPlateData = (plate) => null;
|
||||||
9
frontend/src/components/Button.jsx
Normal file
9
frontend/src/components/Button.jsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Button = ({ text, onClick }) => (
|
||||||
|
<button className="button light" type="button" onClick={onClick}>
|
||||||
|
{text}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Button;
|
||||||
6
frontend/src/components/Loader.jsx
Normal file
6
frontend/src/components/Loader.jsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import '@style/spinner.scss';
|
||||||
|
|
||||||
|
const Loader = () => (<div className="loader">Loading...</div>);
|
||||||
|
|
||||||
|
export default Loader;
|
||||||
108
frontend/src/components/camera/CameraContainer.jsx
Normal file
108
frontend/src/components/camera/CameraContainer.jsx
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import React, {
|
||||||
|
useState, useEffect, useRef, useCallback,
|
||||||
|
} from 'react';
|
||||||
|
import Webcam from 'react-webcam';
|
||||||
|
import FacingMode from '@constant/FacingMode';
|
||||||
|
import Loader from '@components/Loader';
|
||||||
|
import '@style/RootContainer.scss';
|
||||||
|
import CameraOptions from './CameraOptions';
|
||||||
|
import Capture from './Capture';
|
||||||
|
|
||||||
|
const CAMERA_OPTIONS = {
|
||||||
|
format: 'image/jpeg',
|
||||||
|
minHeight: 1920,
|
||||||
|
minWidth: 1080,
|
||||||
|
quality: 0.75,
|
||||||
|
defaultView: FacingMode.FRONT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CameraContainer = () => {
|
||||||
|
const ref = useRef(null);
|
||||||
|
const [imgSrc, setImgSrc] = useState(null);
|
||||||
|
const [captureError, setCaptureError] = useState(null);
|
||||||
|
const [videoInputs, setVideoInputs] = useState([]);
|
||||||
|
const [resetCameraView, setResetCameraView] = useState(false);
|
||||||
|
const [videoConstraints, setVideoConstraints] = useState({
|
||||||
|
facingMode: CAMERA_OPTIONS.defaultView,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const gotDevices = (mediaDevices) => new Promise((resolve, reject) => {
|
||||||
|
const availableVideoInputs = mediaDevices
|
||||||
|
.filter(({ kind }) => kind === 'videoinput')
|
||||||
|
.map(({ deviceId, label }) => ({ deviceId, label }));
|
||||||
|
if (availableVideoInputs.length > 0) {
|
||||||
|
resolve(availableVideoInputs);
|
||||||
|
} else {
|
||||||
|
reject(new Error('ERR::NO_MEDIA_TO_STREAM'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
navigator.mediaDevices
|
||||||
|
.enumerateDevices()
|
||||||
|
.then(gotDevices)
|
||||||
|
.then((availableVideoInputs) => setVideoInputs({ availableVideoInputs }))
|
||||||
|
.catch((err) => console.error(err));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const changeCameraView = () => {
|
||||||
|
if (videoInputs.length === 1) {
|
||||||
|
console.error('ERR::AVAILABLE_MEDIA_STREAMS_IS_1');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setResetCameraView(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const { facingMode } = videoConstraints;
|
||||||
|
const newFacingMode = facingMode === FacingMode.FRONT ? FacingMode.REAR : FacingMode.FRONT;
|
||||||
|
setResetCameraView(false);
|
||||||
|
setVideoConstraints({ ...videoConstraints, facingMode: newFacingMode });
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
const capture = useCallback(() => {
|
||||||
|
const imageSrc = ref.current.getScreenshot();
|
||||||
|
setImgSrc(imageSrc);
|
||||||
|
if (!imageSrc) {
|
||||||
|
setCaptureError(['Failed to capture camera. Please try again.']);
|
||||||
|
} else {
|
||||||
|
setCaptureError(null);
|
||||||
|
}
|
||||||
|
}, [ref, setImgSrc]);
|
||||||
|
|
||||||
|
const onBackClick = () => setImgSrc(null);
|
||||||
|
|
||||||
|
const cameraView = () => (
|
||||||
|
<>
|
||||||
|
<div className="row">
|
||||||
|
{resetCameraView ? (
|
||||||
|
<Loader />
|
||||||
|
) : (
|
||||||
|
<Webcam
|
||||||
|
mirrored={false}
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
audio={false}
|
||||||
|
ref={ref}
|
||||||
|
screenshotFormat={CAMERA_OPTIONS.format}
|
||||||
|
minScreenshotWidth={CAMERA_OPTIONS.minWidth}
|
||||||
|
minScreenshotHeight={CAMERA_OPTIONS.minHeight}
|
||||||
|
screenshotQuality={CAMERA_OPTIONS.quality}
|
||||||
|
videoConstraints={videoConstraints} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<CameraOptions capture={capture} changeCameraView={changeCameraView} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{imgSrc
|
||||||
|
? <Capture imgSrc={imgSrc} error={captureError} onBackClick={onBackClick} />
|
||||||
|
: cameraView()}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CameraContainer;
|
||||||
11
frontend/src/components/camera/CameraOptions.jsx
Normal file
11
frontend/src/components/camera/CameraOptions.jsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Button from '@components/Button';
|
||||||
|
|
||||||
|
const CameraOptions = ({ capture, changeCameraView }) => (
|
||||||
|
<div className="row button-container">
|
||||||
|
<Button text="Switch camera" onClick={changeCameraView} />
|
||||||
|
<Button text="Take image" onClick={capture} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default CameraOptions;
|
||||||
32
frontend/src/components/camera/Capture.jsx
Normal file
32
frontend/src/components/camera/Capture.jsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Loader from '@components/Loader';
|
||||||
|
import { getPlateRecognized } from '@actions/CaptureActions';
|
||||||
|
import Button from '@components/Button';
|
||||||
|
|
||||||
|
const UploadCapture = ({ imgSrc, onBackClick }) => {
|
||||||
|
const onUploadClick = () => {
|
||||||
|
getPlateRecognized(imgSrc);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
<div className="row">
|
||||||
|
<img src={imgSrc} alt="captured" />
|
||||||
|
</div>
|
||||||
|
<div className="row button-container">
|
||||||
|
<Button text="Back" onClick={onBackClick} />
|
||||||
|
<Button text="Upload" onClick={onUploadClick} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Capture = ({
|
||||||
|
imgSrc, isCapturing, error, onBackClick,
|
||||||
|
}) => (
|
||||||
|
<div className="capture-container row">
|
||||||
|
{isCapturing && (<Loader />)}
|
||||||
|
{error ? (<p>{error}</p>) : (<UploadCapture imgSrc={imgSrc} onBackClick={onBackClick} />)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Capture;
|
||||||
6
frontend/src/constant/FacingMode.js
Normal file
6
frontend/src/constant/FacingMode.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
FRONT: 'user',
|
||||||
|
REAR: {
|
||||||
|
exact: 'environment',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,90 +1,14 @@
|
|||||||
import React, {
|
import React from 'react';
|
||||||
useState, useRef, useEffect, useCallback,
|
import CameraContainer from '@components/camera/CameraContainer';
|
||||||
} from 'react';
|
import '@style/RootContainer.scss';
|
||||||
import Webcam from 'react-webcam';
|
|
||||||
|
|
||||||
import '@style/RootContainer';
|
|
||||||
|
|
||||||
const RootContainer = () => {
|
const RootContainer = () => {
|
||||||
const webcamRef = useRef(null);
|
console.log('Hello wlrld');
|
||||||
const [videoInputs, setVideoInputs] = useState([]);
|
|
||||||
const [resetCameraView, setResetCameraView] = useState(false);
|
|
||||||
const [videoConstraints, setVideoConstraints] = useState({
|
|
||||||
facingMode: { exact: 'environment' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const [imgSrc, setImgSrc] = useState(null);
|
|
||||||
|
|
||||||
const capture = useCallback(() => {
|
|
||||||
const imageSrc = webcamRef.current.getScreenshot();
|
|
||||||
setImgSrc(imageSrc);
|
|
||||||
}, [webcamRef, setImgSrc]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const gotDevices = (mediaDevices) => new Promise((resolve, reject) => {
|
|
||||||
const availableVideoInputs = [];
|
|
||||||
mediaDevices.forEach((mediaDevice) => {
|
|
||||||
if (mediaDevice.kind === 'videoinput') {
|
|
||||||
availableVideoInputs.push({
|
|
||||||
deviceId: mediaDevice.deviceId,
|
|
||||||
label: mediaDevice.label,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (availableVideoInputs.length > 0) {
|
|
||||||
resolve(availableVideoInputs);
|
|
||||||
} else {
|
|
||||||
reject(new Error('ERR::NO_MEDIA_TO_STREAM'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
navigator.mediaDevices
|
|
||||||
.enumerateDevices()
|
|
||||||
.then(gotDevices)
|
|
||||||
.then((availableVideoInputs) => setVideoInputs({ availableVideoInputs }))
|
|
||||||
.catch((err) => console.error(err));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const changeCameraView = () => {
|
|
||||||
if (videoInputs.length === 1) {
|
|
||||||
return console.error('ERR::AVAILABLE_MEDIA_STREAMS_IS_1');
|
|
||||||
}
|
|
||||||
|
|
||||||
setResetCameraView(true);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const { facingMode } = videoConstraints;
|
|
||||||
const newFacingMode = facingMode === 'user' ? { exact: 'environment' } : 'user';
|
|
||||||
setResetCameraView(false);
|
|
||||||
setVideoConstraints({ ...videoConstraints, facingMode: newFacingMode });
|
|
||||||
}, 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="container root-container">
|
||||||
{resetCameraView ? (
|
<div className="header" />
|
||||||
'Loading...'
|
<CameraContainer />
|
||||||
) : (
|
</div>
|
||||||
<Webcam
|
|
||||||
audio={false}
|
|
||||||
height="100%"
|
|
||||||
ref={webcamRef}
|
|
||||||
screenshotFormat="image/png"
|
|
||||||
minScreenshotWidth={1080}
|
|
||||||
minScreenshotHeight={1920}
|
|
||||||
screenshotQuality={1}
|
|
||||||
width="100%"
|
|
||||||
videoConstraints={videoConstraints} />
|
|
||||||
)}
|
|
||||||
<button type="button" onClick={changeCameraView}>
|
|
||||||
Switch camera
|
|
||||||
</button>
|
|
||||||
<button type="button" onClick={capture}>
|
|
||||||
Take image
|
|
||||||
</button>
|
|
||||||
{imgSrc && (<img src={imgSrc} />)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
42
frontend/src/hook/useCanvas.js
Normal file
42
frontend/src/hook/useCanvas.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
// Path2D for a Heart SVG
|
||||||
|
const heartSVG = 'M0 200 v-200 h200 a100,100 90 0,1 0,200 a100,100 90 0,1 -200,0 z';
|
||||||
|
const SVG_PATH = new Path2D(heartSVG);
|
||||||
|
|
||||||
|
// Scaling Constants for Canvas
|
||||||
|
const SCALE = 0.1;
|
||||||
|
const OFFSET = 80;
|
||||||
|
export const canvasWidth = window.innerWidth * 0.7;
|
||||||
|
export const canvasHeight = window.innerHeight * 0.7;
|
||||||
|
|
||||||
|
export function draw(ctx, location) {
|
||||||
|
console.log('attempting to draw');
|
||||||
|
ctx.fillStyle = 'red';
|
||||||
|
ctx.shadowColor = 'blue';
|
||||||
|
ctx.shadowBlur = 15;
|
||||||
|
ctx.save();
|
||||||
|
ctx.scale(SCALE, SCALE);
|
||||||
|
ctx.translate(location.x / SCALE - OFFSET, location.y / SCALE - OFFSET);
|
||||||
|
ctx.rotate(225 * Math.PI / 180);
|
||||||
|
ctx.fill(SVG_PATH);
|
||||||
|
// .restore(): Canvas 2D API restores the most recently saved canvas state
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCanvas() {
|
||||||
|
const canvasRef = useRef(null);
|
||||||
|
const [coordinates, setCoordinates] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const canvasObj = canvasRef.current;
|
||||||
|
const ctx = canvasObj.getContext('2d');
|
||||||
|
// clear the canvas area before rendering the coordinates held in state
|
||||||
|
ctx.clearRect(0, 0, canvasObj.parentNode.clientWidth, canvasObj.parentNode.clientHeight);
|
||||||
|
|
||||||
|
// draw all coordinates held in state
|
||||||
|
coordinates.forEach((coordinate) => { draw(ctx, coordinate); });
|
||||||
|
});
|
||||||
|
|
||||||
|
return [coordinates, setCoordinates, canvasRef, canvasWidth, canvasHeight];
|
||||||
|
}
|
||||||
@@ -1,10 +1,65 @@
|
|||||||
|
@import 'camphor.scss';
|
||||||
@import 'palette.scss';
|
@import 'palette.scss';
|
||||||
@import 'constants.scss';
|
@import 'constants.scss';
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: 'Roboto';
|
font-family: 'Camphor' !important;
|
||||||
|
font: 400 13.333px 'Camphor' !important;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
background-color: $orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root-container {
|
||||||
|
//box-shadow: 0 30px 40px rgba(0,0,0,.1);
|
||||||
|
padding: 2em;
|
||||||
|
margin-top: 2em;
|
||||||
|
height: 90vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background-image: url('../../assets/images/Maanteeamet.png');
|
||||||
|
background-size: cover;
|
||||||
|
height: 120px;
|
||||||
|
margin-bottom: 3em;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
margin-top: 1em;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0.25em;
|
||||||
|
font-family: inherit;
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
background-color: rgba(255, 121, 121, 0.5);
|
||||||
|
border: 1px solid rgba(255, 121, 121, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.capture-container {
|
||||||
|
canvas {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
frontend/src/style/camphor.scss
Normal file
46
frontend/src/style/camphor.scss
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
$orange: #fed8b1;
|
||||||
|
|||||||
46
frontend/src/style/spinner.scss
Normal file
46
frontend/src/style/spinner.scss
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
.loader,
|
||||||
|
.loader:after {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 10em;
|
||||||
|
height: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
margin: 60px auto;
|
||||||
|
font-size: 10px;
|
||||||
|
position: relative;
|
||||||
|
text-indent: -9999em;
|
||||||
|
border-top: 1.1em solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-right: 1.1em solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
|
||||||
|
border-left: 1.1em solid #ffffff;
|
||||||
|
-webkit-transform: translateZ(0);
|
||||||
|
-ms-transform: translateZ(0);
|
||||||
|
transform: translateZ(0);
|
||||||
|
-webkit-animation: load8 1.1s infinite linear;
|
||||||
|
animation: load8 1.1s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes load8 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes load8 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable import/no-extraneous-dependencies */
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
|
||||||
const { ProgressPlugin } = require('webpack');
|
const { ProgressPlugin, EnvironmentPlugin } = require('webpack');
|
||||||
const convert = require('koa-connect');
|
const convert = require('koa-connect');
|
||||||
const history = require('connect-history-api-fallback');
|
const history = require('connect-history-api-fallback');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
@@ -71,6 +71,7 @@ module.exports = {
|
|||||||
extensions: ['*', '.js', '.jsx', '.css', '.scss'],
|
extensions: ['*', '.js', '.jsx', '.css', '.scss'],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new EnvironmentPlugin(['NODE_ENV', 'API_BASE_PATH']),
|
||||||
new ProgressPlugin(),
|
new ProgressPlugin(),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: commonPaths.templatePath,
|
template: commonPaths.templatePath,
|
||||||
|
|||||||
@@ -46,44 +46,44 @@ module.exports = {
|
|||||||
contentBase: commonPaths.outputPath,
|
contentBase: commonPaths.outputPath,
|
||||||
compress: true,
|
compress: true,
|
||||||
hot: true,
|
hot: true,
|
||||||
port: 3001,
|
port: 3000,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new HotModuleReplacementPlugin(),
|
new HotModuleReplacementPlugin(),
|
||||||
new HardSourceWebpackPlugin({
|
// new HardSourceWebpackPlugin({
|
||||||
// Either an absolute path or relative to webpack's options.context.
|
// // Either an absolute path or relative to webpack's options.context.
|
||||||
cacheDirectory: commonPaths.cachePath,
|
// cacheDirectory: commonPaths.cachePath,
|
||||||
// Either a string of object hash function given a webpack config.
|
// // Either a string of object hash function given a webpack config.
|
||||||
// node-object-hash on npm can be used to build this.
|
// // node-object-hash on npm can be used to build this.
|
||||||
configHash: (webpackConfig) => require('node-object-hash')({ // eslint-disable-line
|
// configHash: (webpackConfig) => require('node-object-hash')({ // eslint-disable-line
|
||||||
sort: false,
|
// sort: false,
|
||||||
}).hash(webpackConfig),
|
// }).hash(webpackConfig),
|
||||||
// Either false, a string, an object, or a project hashing function.
|
// // Either false, a string, an object, or a project hashing function.
|
||||||
environmentHash: {
|
// environmentHash: {
|
||||||
root: process.cwd(),
|
// root: process.cwd(),
|
||||||
directories: [],
|
// directories: [],
|
||||||
files: [
|
// files: [
|
||||||
// Cache will get an unique hash based on those files
|
// // Cache will get an unique hash based on those files
|
||||||
// if either of them changes, new cache must be generated
|
// // if either of them changes, new cache must be generated
|
||||||
'package-lock.json',
|
// 'package-lock.json',
|
||||||
'.babelrc.js',
|
// '.babelrc.js',
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
info: {
|
// info: {
|
||||||
mode: 'none',
|
// mode: 'none',
|
||||||
level: 'debug',
|
// level: 'debug',
|
||||||
},
|
// },
|
||||||
// Clean up large, old caches automatically.
|
// // Clean up large, old caches automatically.
|
||||||
cachePrune: {
|
// cachePrune: {
|
||||||
// Caches younger than `maxAge` are not considered for deletion.
|
// // Caches younger than `maxAge` are not considered for deletion.
|
||||||
// They must be at least this old in milliseconds.
|
// // They must be at least this old in milliseconds.
|
||||||
maxAge: 3 * 60 * 60 * 1000, // 3 hours
|
// maxAge: 3 * 60 * 60 * 1000, // 3 hours
|
||||||
// All caches together must be larger than `sizeThreshold` before any
|
// // All caches together must be larger than `sizeThreshold` before any
|
||||||
// caches will be deleted.
|
// // caches will be deleted.
|
||||||
// Together they must be at least this big in bytes.
|
// // Together they must be at least this big in bytes.
|
||||||
sizeThreshold: 50 * 1024 * 1024, // 50 MB
|
// sizeThreshold: 50 * 1024 * 1024, // 50 MB
|
||||||
},
|
// },
|
||||||
}),
|
// }),
|
||||||
new BundleAnalyzerPlugin({
|
new BundleAnalyzerPlugin({
|
||||||
analyzerPort: 8888,
|
analyzerPort: 8888,
|
||||||
openAnalyzer: false,
|
openAnalyzer: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user