diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..3de69bf40 --- /dev/null +++ b/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + "@babel/plugin-syntax-dynamic-import" + ] +} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..340cc1cfa --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,67 @@ +module.exports = { + root: true, + env: { + browser: true, + es6: true, + node: true, + jest: true + }, + globals: { + t: true, + n: true, + OC: true, + OCA: true, + Vue: true, + VueRouter: true + }, + parserOptions: { + parser: 'babel-eslint', + ecmaVersion: 6 + }, + extends: [ + 'eslint:recommended', + 'plugin:node/recommended', + 'plugin:vue/essential', + 'plugin:vue/recommended', + 'standard' + ], + plugins: ['vue', 'node'], + rules: { + // space before function () + 'space-before-function-paren': ['error', 'never'], + // curly braces always space + 'object-curly-spacing': ['error', 'always'], + // stay consistent with array brackets + 'array-bracket-newline': ['error', 'consistent'], + // 1tbs brace style + 'brace-style': 'error', + // tabs only + indent: ['error', 'tab'], + 'no-tabs': 0, + 'vue/html-indent': ['error', 'tab'], + // only debug console + 'no-console': ['error', { allow: ['error', 'warn', 'debug'] }], + // classes blocks + 'padded-blocks': ['error', { classes: 'always' }], + // always have the operator in front + 'operator-linebreak': ['error', 'before'], + // ternary on multiline + 'multiline-ternary': ['error', 'always-multiline'], + // es6 import/export and require + 'node/no-unpublished-require': ['off'], + 'node/no-unsupported-features/es-syntax': ['off'], + // space before self-closing elements + 'vue/html-closing-bracket-spacing': 'error', + // code spacing with attributes + 'vue/max-attributes-per-line': [ + 'error', + { + singleline: 3, + multiline: { + max: 3, + allowFirstLine: true + } + } + ] + } +} diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index fed0e4eb0..000000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,43 +0,0 @@ -root: true - -extends: - - eslint:recommended - -env: - browser: true - amd: true - es6: true - -globals: - global: false - app: false - angular: false - $: false - escapeHTML: false - OC: false - OCA: false - t: false - oc_current_user: false - oc_requesttoken: false - Clipboard: false - oc_defaults: false - -parserOptions: - ecmaVersion: 6 - sourceType: "module" - -rules: - curly: error - eqeqeq: ["error", "smart"] - guard-for-in: error - no-console: off - no-fallthrough: error - no-mixed-spaces-and-tabs: error - no-unused-vars: warn - no-useless-escape: warn - no-use-before-define: error - semi: ["error", "always"] - indent: - - error - - tab - - SwitchCase: 1 diff --git a/.gitignore b/.gitignore index a6073ac05..46cafbc9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +node_modules/* +js/*deck.js +js/*deck.js.map + js/node_modules/* js/vendor/ js/public/ diff --git a/package.json b/package.json new file mode 100644 index 000000000..0b3cfcc47 --- /dev/null +++ b/package.json @@ -0,0 +1,99 @@ +{ + "name": "deck", + "description": "", + "version": "1.0.0", + "authors": [ + { + "name": "Julius Härtl", + "email": "jus@bitgrid.net", + "role": "Developer" + }, + { + "name": "Michael Weimann", + "email": "mail@michael-weimann.eu", + "role": "Developer" + } + ], + "license": "agpl", + "private": true, + "scripts": { + "dev": "webpack --config webpack.dev.js", + "watch": "webpack --progress --watch --config webpack.dev.js", + "build": "webpack --progress --hide-modules --config webpack.prod.js", + "lint": "eslint --ext .js,.vue src tests", + "lint:fix": "eslint --ext .js,.vue src tests --fix", + "test": "jest", + "test:coverage": "jest --coverage" + }, + "dependencies": { + "@babel/polyfill": "^7.0.0", + "nextcloud-axios": "^0.1.2", + "nextcloud-server": "^0.15.9", + "nextcloud-vue": "^0.4.2", + "vue": "^2.5.16", + "vue-click-outside": "^1.0.7", + "vue-infinite-loading": "^2.4.1", + "vue-router": "^3.0.1", + "vuex": "^3.0.1", + "vuex-router-sync": "^5.0.0" + }, + "browserslist": [ + "last 2 versions", + "not ie <= 11" + ], + "engines": { + "node": ">=10.0.0" + }, + "devDependencies": { + "@babel/core": "^7.1.2", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/preset-env": "^7.1.0", + "@vue/test-utils": "^1.0.0-beta.25", + "babel-eslint": "^8.2.5", + "babel-jest": "^23.6.0", + "babel-loader": "^8.0.4", + "css-loader": "^0.28.11", + "eslint": "^4.19.1", + "eslint-config-standard": "^11.0.0", + "eslint-friendly-formatter": "^4.0.1", + "eslint-loader": "^2.1.1", + "eslint-plugin-import": "^2.13.0", + "eslint-plugin-node": "^7.0.1", + "eslint-plugin-promise": "^3.8.0", + "eslint-plugin-standard": "^3.1.0", + "eslint-plugin-vue": "^4.5.0", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.11", + "jest": "^23.6.0", + "jest-serializer-vue": "^2.0.2", + "mini-css-extract-plugin": "^0.4.4", + "prettier-eslint": "^8.8.2", + "raw-loader": "^0.5.1", + "stylelint": "^8.4.0", + "stylelint-config-recommended-scss": "^3.2.0", + "stylelint-webpack-plugin": "^0.10.5", + "vue-jest": "^2.6.0", + "vue-loader": "^15.4.2", + "vue-style-loader": "^4.1.1", + "vue-template-compiler": "^2.5.16", + "webpack": "^4.23.1", + "webpack-cli": "^3.1.2", + "webpack-merge": "^4.1.2" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "vue" + ], + "moduleNameMapper": { + "^@/(.*)$": "/src/$1" + }, + "transform": { + "^.+\\.js$": "/node_modules/babel-jest", + ".*\\.(vue)$": "/node_modules/vue-jest" + }, + "snapshotSerializers": [ + "/node_modules/jest-serializer-vue" + ] + } +} diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 000000000..8fcbaa2f0 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/main.js b/src/main.js new file mode 100644 index 000000000..a12f0efa9 --- /dev/null +++ b/src/main.js @@ -0,0 +1,53 @@ +/* + * @copyright Copyright (c) 2018 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +import Vue from 'vue' +import App from './App' +import router from './router' +import store from './store/main' +import { sync } from 'vuex-router-sync' +import { translate, translatePlural } from 'nextcloud-server/dist/l10n' +import { generateFilePath } from 'nextcloud-server/dist/router' +import VTooltip from 'v-tooltip' + +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken) +// eslint-disable-next-line +__webpack_public_path__ = generateFilePath('deck', '', 'js/') + +sync(store, router) + +Vue.mixin({ + methods: { + t: translate, + n: translatePlural + } +}) + +Vue.use(VTooltip) + +/* eslint-disable-next-line no-new */ +new Vue({ + el: '#content', + router, + store, + render: h => h(App) +}) diff --git a/src/router.js b/src/router.js new file mode 100644 index 000000000..61c2ef5ef --- /dev/null +++ b/src/router.js @@ -0,0 +1,51 @@ +/* + * @copyright Copyright (c) 2018 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import Vue from 'vue' +import Router from 'vue-router' +import { generateUrl } from 'nextcloud-server/dist/router' + +const Main = () => import('./views/Main') + +Vue.use(Router) + +export default new Router({ + base: generateUrl('/apps/deck/'), + linkActiveClass: 'active', + routes: [ + { + path: '/', + name: 'main', + component: Main + }, + { + path: '/boards', + name: 'boards', + component: Main + }, + { + path: '/boards/archived', + name: 'boards.archived', + component: Main + } + ] +}) diff --git a/src/store/main.js b/src/store/main.js new file mode 100644 index 000000000..b6c4c1600 --- /dev/null +++ b/src/store/main.js @@ -0,0 +1,34 @@ +/* + * @copyright Copyright (c) 2018 Julius Härtl + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +const debug = process.env.NODE_ENV !== 'production' + +export default new Vuex.Store({ + modules: { + }, + strict: debug +}) diff --git a/src/views/Board.vue b/src/views/Board.vue new file mode 100644 index 000000000..d5c974934 --- /dev/null +++ b/src/views/Board.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/src/views/List.vue b/src/views/List.vue new file mode 100644 index 000000000..fdfb710c5 --- /dev/null +++ b/src/views/List.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/src/views/Main.vue b/src/views/Main.vue new file mode 100644 index 000000000..d88ea8702 --- /dev/null +++ b/src/views/Main.vue @@ -0,0 +1,130 @@ + + + + + + + diff --git a/src/views/Sidebar.vue b/src/views/Sidebar.vue new file mode 100644 index 000000000..a63cb70ad --- /dev/null +++ b/src/views/Sidebar.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/webpack.common.js b/webpack.common.js new file mode 100644 index 000000000..407715ca6 --- /dev/null +++ b/webpack.common.js @@ -0,0 +1,42 @@ +const path = require('path'); +const { VueLoaderPlugin } = require('vue-loader'); + +module.exports = { + entry: path.join(__dirname, 'src', 'main.js'), + output: { + path: path.resolve(__dirname, './js'), + publicPath: '/js/', + filename: 'deck.js' + }, + module: { + rules: [ + { + test: /\.css$/, + use: ['vue-style-loader', 'css-loader'] + }, + { + test: /\.vue$/, + loader: 'vue-loader' + }, + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/ + }, + { + test: /\.(png|jpg|gif|svg)$/, + loader: 'file-loader', + options: { + name: '[name].[ext]?[hash]' + } + } + ] + }, + plugins: [new VueLoaderPlugin()], + resolve: { + alias: { + vue$: 'vue/dist/vue.esm.js' + }, + extensions: ['*', '.js', '.vue', '.json'] + } +}; diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 000000000..49291d777 --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,12 @@ +const merge = require('webpack-merge'); +const common = require('./webpack.common.js'); + +module.exports = merge(common, { + mode: 'development', + devServer: { + historyApiFallback: true, + noInfo: true, + overlay: true + }, + devtool: 'source-map', +}) diff --git a/webpack.prod.js b/webpack.prod.js new file mode 100644 index 000000000..f081567bd --- /dev/null +++ b/webpack.prod.js @@ -0,0 +1,7 @@ +const merge = require('webpack-merge') +const common = require('./webpack.common.js') + +module.exports = merge(common, { + mode: 'production', + devtool: '#source-map' +})