diff --git a/build/webpack.base.config.js b/build/webpack.base.config.js
index 360f1df..180ae23 100644
--- a/build/webpack.base.config.js
+++ b/build/webpack.base.config.js
@@ -21,10 +21,6 @@ module.exports = {
test: /\.vue$/,
loader: 'vue-loader',
},
- {
- resourceQuery: /^\?vue/,
- use: path.resolve(__dirname, 'includer.js')
- },
{
test: /\.js$/,
loader: 'babel-loader',
diff --git a/build/webpack.dev.config.js b/build/webpack.dev.config.js
index f27ee9b..8e0c014 100644
--- a/build/webpack.dev.config.js
+++ b/build/webpack.dev.config.js
@@ -1,5 +1,6 @@
const path = require('path');
const webpack = require('webpack');
+const pckg = require('../package.json');
const { merge } = require('webpack-merge');
const baseWpConfig = require('./webpack.base.config');
@@ -8,7 +9,7 @@ baseWpConfig.entry.unshift('webpack-hot-middleware/client');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
-const publicDir = path.resolve(__dirname, '../server/public');
+const publicDir = path.resolve(__dirname, `../server/.${pckg.name}/public`);
const clientDir = path.resolve(__dirname, '../client');
module.exports = merge(baseWpConfig, {
diff --git a/client/assets/robots.txt b/client/assets/robots.txt
new file mode 100644
index 0000000..4d6e74a
--- /dev/null
+++ b/client/assets/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /#
diff --git a/client/components/App.vue b/client/components/App.vue
new file mode 100644
index 0000000..88de668
--- /dev/null
+++ b/client/components/App.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/components/Search/Search.vue b/client/components/Search/Search.vue
new file mode 100644
index 0000000..3c664f3
--- /dev/null
+++ b/client/components/Search/Search.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
diff --git a/client/components/fonts/web-default.ttf b/client/components/fonts/web-default.ttf
new file mode 100644
index 0000000..4a3a5e6
Binary files /dev/null and b/client/components/fonts/web-default.ttf differ
diff --git a/client/components/fonts/web-default.woff b/client/components/fonts/web-default.woff
new file mode 100644
index 0000000..b2ac07b
Binary files /dev/null and b/client/components/fonts/web-default.woff differ
diff --git a/client/components/share/Dialog.vue b/client/components/share/Dialog.vue
new file mode 100644
index 0000000..7a93bac
--- /dev/null
+++ b/client/components/share/Dialog.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/components/share/Notify.vue b/client/components/share/Notify.vue
new file mode 100644
index 0000000..92c3759
--- /dev/null
+++ b/client/components/share/Notify.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
diff --git a/client/components/share/StdDialog.vue b/client/components/share/StdDialog.vue
new file mode 100644
index 0000000..384585d
--- /dev/null
+++ b/client/components/share/StdDialog.vue
@@ -0,0 +1,361 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Отмена
+
+
+ OK
+
+
+
+
+
+
+
+
+
+
+
+
+ Отмена
+
+
+ OK
+
+
+
+
+
+
+
+
+
+
+
+
+ Нет
+
+
{{ hotKeyCode }}
+
+
+
+
+
+ Отмена
+
+
+ OK
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/components/vueComponent.js b/client/components/vueComponent.js
new file mode 100644
index 0000000..67f8c2e
--- /dev/null
+++ b/client/components/vueComponent.js
@@ -0,0 +1,52 @@
+import { defineComponent } from 'vue';
+import _ from 'lodash';
+
+export default function(componentClass) {
+ const comp = {};
+ const obj = new componentClass();
+
+ //data, options, props
+ const data = {};
+ for (const prop of Object.getOwnPropertyNames(obj)) {
+ if (['_options', '_props'].includes(prop)) {//meta props
+ if (prop === '_options') {
+ const options = obj[prop];
+ for (const optName of ['components', 'watch', 'emits']) {
+ if (options[optName]) {
+ comp[optName] = options[optName];
+ }
+ }
+ } else if (prop === '_props') {
+ comp['props'] = obj[prop];
+ }
+ } else {//usual prop
+ data[prop] = obj[prop];
+ }
+ }
+ comp.data = () => _.cloneDeep(data);
+
+ //methods
+ const classProto = Object.getPrototypeOf(obj);
+ const classMethods = Object.getOwnPropertyNames(classProto);
+ const methods = {};
+ const computed = {};
+ for (const method of classMethods) {
+ const desc = Object.getOwnPropertyDescriptor(classProto, method);
+ if (desc.get) {//has getter, computed
+ computed[method] = {get: desc.get};
+ if (desc.set)
+ computed[method].set = desc.set;
+ } else if ( ['beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'activated',//life cycle hooks
+ 'deactivated', 'beforeUnmount', 'unmounted', 'errorCaptured', 'renderTracked', 'renderTriggered',//life cycle hooks
+ 'setup'].includes(method) ) {
+ comp[method] = obj[method];
+ } else if (method !== 'constructor') {//usual
+ methods[method] = obj[method];
+ }
+ }
+ comp.methods = methods;
+ comp.computed = computed;
+
+ //console.log(comp);
+ return defineComponent(comp);
+}
diff --git a/client/index.html.template b/client/index.html.template
new file mode 100644
index 0000000..7f9a5e9
--- /dev/null
+++ b/client/index.html.template
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/main.js b/client/main.js
new file mode 100644
index 0000000..a00b092
--- /dev/null
+++ b/client/main.js
@@ -0,0 +1,16 @@
+import { createApp } from 'vue';
+
+import router from './router';
+import store from './store';
+import q from './quasar';
+
+import App from './components/App.vue';
+
+const app = createApp(App);
+
+app.use(router);
+app.use(store);
+app.use(q.quasar, q.options);
+q.init();
+
+app.mount('#app');
diff --git a/client/quasar.js b/client/quasar.js
new file mode 100644
index 0000000..0702203
--- /dev/null
+++ b/client/quasar.js
@@ -0,0 +1,97 @@
+import 'quasar/dist/quasar.css';
+
+import Quasar from 'quasar/src/vue-plugin.js';
+//config
+const config = {};
+
+//components
+//import {QLayout} from 'quasar/src/components/layout';
+//import {QPageContainer, QPage} from 'quasar/src/components/page';
+//import {QDrawer} from 'quasar/src/components/drawer';
+
+//import {QCircularProgress} from 'quasar/src/components/circular-progress';
+import {QInput} from 'quasar/src/components/input';
+import {QBtn} from 'quasar/src/components/btn';
+//import {QBtnGroup} from 'quasar/src/components/btn-group';
+//import {QBtnToggle} from 'quasar/src/components/btn-toggle';
+import {QIcon} from 'quasar/src/components/icon';
+//import {QSlider} from 'quasar/src/components/slider';
+//import {QTabs, QTab} from 'quasar/src/components/tabs';
+//import {QTabPanels, QTabPanel} from 'quasar/src/components/tab-panels';
+//import {QSeparator} from 'quasar/src/components/separator';
+//import {QList} from 'quasar/src/components/item';
+//import {QItem, QItemSection, QItemLabel} from 'quasar/src/components/item';
+//import {QTooltip} from 'quasar/src/components/tooltip';
+//import {QSpinner} from 'quasar/src/components/spinner';
+//import {QTable, QTh, QTr, QTd} from 'quasar/src/components/table';
+//import {QCheckbox} from 'quasar/src/components/checkbox';
+//import {QSelect} from 'quasar/src/components/select';
+//import {QColor} from 'quasar/src/components/color';
+//import {QPopupProxy} from 'quasar/src/components/popup-proxy';
+import {QDialog} from 'quasar/src/components/dialog';
+//import {QChip} from 'quasar/src/components/chip';
+//import {QTree} from 'quasar/src/components/tree';
+//import {QVirtualScroll} from 'quasar/src/components/virtual-scroll';
+
+//import {QExpansionItem} from 'quasar/src/components/expansion-item';
+
+const components = {
+ //QLayout,
+ //QPageContainer, QPage,
+ //QDrawer,
+
+ //QCircularProgress,
+ QInput,
+ QBtn,
+ //QBtnGroup,
+ //QBtnToggle,
+ QIcon,
+ //QSlider,
+ //QTabs, QTab,
+ //QTabPanels, QTabPanel,
+ //QSeparator,
+ //QList,
+ //QItem, QItemSection, QItemLabel,
+ //QTooltip,
+ //QSpinner,
+ //QTable, QTh, QTr, QTd,
+ //QCheckbox,
+ //QSelect,
+ //QColor,
+ //QPopupProxy,
+ QDialog,
+ //QChip,
+ //QTree,
+ //QExpansionItem,
+ //QVirtualScroll,
+};
+
+//directives
+//import Ripple from 'quasar/src/directives/Ripple';
+import ClosePopup from 'quasar/src/directives/ClosePopup';
+
+const directives = {/*Ripple, */ClosePopup};
+
+//plugins
+//import AppFullscreen from 'quasar/src/plugins/AppFullscreen';
+//import Notify from 'quasar/src/plugins/Notify';
+
+const plugins = {
+ //AppFullscreen,
+ //Notify,
+};
+
+//icons
+//import '@quasar/extras/fontawesome-v5/fontawesome-v5.css';
+//import fontawesomeV5 from 'quasar/icon-set/fontawesome-v5.js'
+
+import '@quasar/extras/line-awesome/line-awesome.css';
+import lineAwesome from 'quasar/icon-set/line-awesome.js'
+
+export default {
+ quasar: Quasar,
+ options: { config, components, directives, plugins },
+ init: () => {
+ Quasar.iconSet.set(lineAwesome);
+}
+};
\ No newline at end of file
diff --git a/client/router.js b/client/router.js
new file mode 100644
index 0000000..3fb73bb
--- /dev/null
+++ b/client/router.js
@@ -0,0 +1,38 @@
+import { createRouter, createWebHashHistory } from 'vue-router';
+import _ from 'lodash';
+
+const Search = () => import('./components/Search/Search.vue');
+
+const myRoutes = [
+ ['/', Search],
+ ['/:pathMatch(.*)*', null, null, '/'],
+];
+
+let routes = {};
+
+for (let route of myRoutes) {
+ const [path, component, name, redirect] = route;
+ let cleanRoute = _.pickBy({path, component, name, redirect}, _.identity);
+
+ let parts = cleanRoute.path.split('~');
+ let f = routes;
+ for (let part of parts) {
+ const curRoute = _.assign({}, cleanRoute, { path: part });
+
+ if (!f.children)
+ f.children = [];
+ let r = f.children;
+
+ f = _.find(r, {path: part});
+ if (!f) {
+ r.push(curRoute);
+ f = curRoute;
+ }
+ }
+}
+routes = routes.children;
+
+export default createRouter({
+ history: createWebHashHistory(),
+ routes
+});
diff --git a/client/share/utils.js b/client/share/utils.js
new file mode 100644
index 0000000..3fe79a0
--- /dev/null
+++ b/client/share/utils.js
@@ -0,0 +1,30 @@
+//import _ from 'lodash';
+
+export function sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+export function keyEventToCode(event) {
+ let result = [];
+ let code = event.code;
+
+ const modCode = code.substring(0, 3);
+ if (event.metaKey && modCode != 'Met')
+ result.push('Meta');
+ if (event.ctrlKey && modCode != 'Con')
+ result.push('Ctrl');
+ if (event.shiftKey && modCode != 'Shi')
+ result.push('Shift');
+ if (event.altKey && modCode != 'Alt')
+ result.push('Alt');
+
+ if (modCode == 'Dig') {
+ code = code.substring(5, 6);
+ } else if (modCode == 'Key') {
+ code = code.substring(3, 4);
+ }
+ result.push(code);
+
+ return result.join('+');
+}
+
diff --git a/client/store/index.js b/client/store/index.js
new file mode 100644
index 0000000..06cace6
--- /dev/null
+++ b/client/store/index.js
@@ -0,0 +1,15 @@
+import { createStore } from 'vuex';
+import VuexPersistence from 'vuex-persist';
+
+import root from './root.js';
+
+const debug = process.env.NODE_ENV !== 'production';
+
+const vuexLocal = new VuexPersistence();
+
+export default createStore(Object.assign({}, root, {
+ modules: {
+ },
+ strict: debug,
+ plugins: [vuexLocal.plugin]
+}));
diff --git a/client/store/root.js b/client/store/root.js
new file mode 100644
index 0000000..1cd73ad
--- /dev/null
+++ b/client/store/root.js
@@ -0,0 +1,25 @@
+// initial state
+const state = {
+ apiError: null,
+};
+
+// getters
+const getters = {};
+
+// actions
+const actions = {};
+
+// mutations
+const mutations = {
+ setApiError(state, value) {
+ state.apiError = value;
+ },
+};
+
+export default {
+ namespaced: true,
+ state,
+ getters,
+ actions,
+ mutations
+};
diff --git a/server/config/base.js b/server/config/base.js
index 72d1c28..644f024 100644
--- a/server/config/base.js
+++ b/server/config/base.js
@@ -2,7 +2,7 @@ const path = require('path');
const pckg = require('../../package.json');
const execDir = path.resolve(__dirname, '..');
-const dataDir = `${execDir}/.${pckg.name}/data`;
+const dataDir = `${execDir}/.${pckg.name}`;
module.exports = {
branch: 'unknown',
diff --git a/server/config/production.js b/server/config/production.js
index fd4a516..e649161 100644
--- a/server/config/production.js
+++ b/server/config/production.js
@@ -3,7 +3,7 @@ const pckg = require('../../package.json');
const base = require('./base');
const execDir = path.dirname(process.execPath);
-const dataDir = `${execDir}/.${pckg.name}/data`;
+const dataDir = `${execDir}/.${pckg.name}`;
module.exports = Object.assign({}, base, {
branch: 'production',
diff --git a/server/dev.js b/server/dev.js
index 1ae2dfb..d652348 100644
--- a/server/dev.js
+++ b/server/dev.js
@@ -20,7 +20,7 @@ function webpackDevMiddleware(app) {
function logQueries(app) {
app.use(function(req, res, next) {
const start = Date.now();
- log(`${req.method} ${req.originalUrl} ${JSON.stringify(req.body).substr(0, 4000)}`);
+ log(`${req.method} ${req.originalUrl} ${JSON.stringify(req.body ? req.body : '').substr(0, 4000)}`);
//log(`${JSON.stringify(req.headers, null, 2)}`)
res.once('finish', () => {
log(`${Date.now() - start}ms`);
diff --git a/server/index.js b/server/index.js
index d9473e4..e02a7ef 100644
--- a/server/index.js
+++ b/server/index.js
@@ -105,6 +105,17 @@ async function main() {
function initStatic(app, config) {// eslint-disable-line
//загрузка файлов в /files
//TODO
+
+ app.use(express.static(config.publicDir, {
+ maxAge: '30d',
+
+ /*setHeaders: (res, filePath) => {
+ if (path.dirname(filePath) == filesDir) {
+ res.set('Content-Type', 'application/xml');
+ res.set('Content-Encoding', 'gzip');
+ }
+ },*/
+ }));
}
(async() => {