js boilerplate

This commit is contained in:
Robin Appelman 2017-04-07 16:39:59 +02:00
parent da18093a2d
commit e8e63c2b4a
14 changed files with 421 additions and 0 deletions

14
.babelrc Normal file
View file

@ -0,0 +1,14 @@
{
"presets": [
[
"es2015",
{
"modules": false
}
],
"react"
],
"plugins": [
"react-hot-loader/babel"
]
}

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules/
build/appstore/

49
Makefile Normal file
View file

@ -0,0 +1,49 @@
# Makefile for building the project
app_name=groupfolders
project_dir=$(CURDIR)/../$(app_name)
build_dir=$(project_dir)/build
appstore_dir=$(build_dir)/appstore
package_name=$(app_name)
cert_dir=$(HOME)/.nextcloud/certificates
webpack=node_modules/.bin/webpack
jssources=$(wildcard js/*) $(wildcard js/*/*) $(wildcard css/*/*) $(wildcard css/*)
othersources=$(wildcard appinfo/*) $(wildcard css/*/*) $(wildcard controller/*/*) $(wildcard templates/*/*) $(wildcard log/*/*)
all: build/main.js
clean:
rm -rf $(build_dir)
rm -rf node_modules
node_modules: package.json
npm install --deps
build/main.js: node_modules $(jssources)
NODE_ENV=production $(webpack) --colors --display-error-details --config webpack.prod.config.js
.PHONY: watch
watch: node_modules
node node_modules/.bin/webpack-dev-server --hot --inline --port 3000 --public localcloud.icewind.me:444 --config webpack.dev.config.js
appstore: clean build/main.js package
package: build/appstore/$(package_name).tar.gz
build/appstore/$(package_name).tar.gz: build/main.js $(othersources)
mkdir -p $(appstore_dir)
tar --exclude-vcs \
--exclude=$(appstore_dir) \
--exclude=$(project_dir)/node_modules \
--exclude=$(project_dir)/webpack \
--exclude=$(project_dir)/.gitattributes \
--exclude=$(project_dir)/.gitignore \
--exclude=$(project_dir)/.travis.yml \
--exclude=$(project_dir)/.scrutinizer.yml \
--exclude=$(project_dir)/CONTRIBUTING.md \
--exclude=$(project_dir)/package.json \
--exclude=$(project_dir)/screenshots \
--exclude=$(project_dir)/Makefile \
-cvzf $(appstore_dir)/$(package_name).tar.gz $(project_dir)
openssl dgst -sha512 -sign $(cert_dir)/$(app_name).key $(appstore_dir)/$(app_name).tar.gz | openssl base64

View file

@ -11,6 +11,11 @@
</types>
<namespace>GroupFolders</namespace>
<settings>
<admin>OCA\GroupFolders\Settings\Admin</admin>
<admin-section>OCA\GroupFolders\Settings\Section</admin-section>
</settings>
<dependencies>
<nextcloud min-version="11" max-version="12"/>
</dependencies>

1
img/app-dark.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" viewbox="0 0 32 32"><path style="block-progression:tb;text-transform:none;text-indent:0" d="M9.24 6.67c-1.955 0-3.613 1.43-3.613 3.275.014.583.066 1.302.414 2.823v.037l.038.038c.112.32.275.503.49.753.215.25.47.544.715.79l.075.076c.048.21.107.436.15.64.117.54.105.922.076 1.053-.84.295-1.885.647-2.823 1.054-.526.228-1.002.433-1.392.677-.39.244-.777.43-.903.978a.473.473 0 0 0 0 .076c-.123 1.13-.31 2.793-.452 3.915a.618.618 0 0 0 .3.603c1.704.92 4.32 1.29 6.927 1.28 2.607-.01 5.202-.403 6.85-1.28a.618.618 0 0 0 .3-.603c-.044-.35-.1-1.14-.15-1.92-.05-.778-.09-1.543-.15-1.994a.607.607 0 0 0-.15-.3c-.524-.626-1.306-1.008-2.22-1.393-.836-.352-1.815-.717-2.786-1.13-.055-.12-.11-.473 0-1.016.03-.144.074-.3.113-.45l.263-.3c.216-.248.447-.506.64-.754.192-.25.35-.462.452-.753l.037-.038c.393-1.588.393-2.25.413-2.823v-.037c0-1.845-1.658-3.275-3.613-3.275zm10.336-3.005c-2.85 0-5.268 2.084-5.268 4.774.02.85.096 1.898.604 4.115v.055l.055.055c.162.466.4.733.713 1.097s.687.793 1.043 1.153c.04.042.068.068.11.11.07.306.155.636.22.932.168.788.15 1.346.11 1.537-1.226.43-2.75.942-4.117 1.536-.768.334-1.462.632-2.03.988-.57.356-1.134.625-1.317 1.427a.67.67 0 0 0 0 .11c-.18 1.648-.452 4.07-.66 5.707a.9.9 0 0 0 .44.878c2.48 1.34 6.295 1.88 10.096 1.865s7.584-.586 9.987-1.865a.9.9 0 0 0 .44-.878c-.067-.512-.148-1.665-.22-2.8-.072-1.133-.134-2.25-.22-2.907a.884.884 0 0 0-.22-.44c-.763-.91-1.903-1.468-3.237-2.03-1.217-.513-2.645-1.045-4.06-1.646-.08-.177-.16-.69 0-1.483.042-.212.108-.44.164-.658.133-.15.237-.272.384-.44.315-.36.652-.735.933-1.098.28-.362.51-.673.66-1.097l.053-.055c.574-2.315.574-3.28.604-4.116V8.44c0-2.69-2.418-4.775-5.268-4.775z" color="#000"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

3
js/App.js Normal file
View file

@ -0,0 +1,3 @@
export function App () {
return <div>Group Folders</div>;
}

30
js/index.js Normal file
View file

@ -0,0 +1,30 @@
'use strict';
import {App} from './App';
import {AppContainer} from 'react-hot-loader';
import React from 'react';
import ReactDom from 'react-dom';
// Enable React devtools
window.React = React;
const render = (Component) => {
ReactDom.render(
<AppContainer>
<Component/>
</AppContainer>,
document.getElementById('groupfolders-root')
);
};
$(document).ready(() => {
render(App);
// Hot Module Replacement API
if (module.hot) {
console.log('hoty');
module.hot.accept('./App', () => {
render(App)
});
}
});

View file

@ -0,0 +1,47 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\GroupFolders\Controller;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\TemplateResponse;
class PageController extends Controller {
/**
* @NoCSRFRequired
*
* @return TemplateResponse
*/
public function index() {
$response = new TemplateResponse(
$this->appName,
'index',
[
'appId' => $this->appName
]
);
return $response;
}
}

56
lib/Settings/Admin.php Normal file
View file

@ -0,0 +1,56 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\GroupFolders\Settings;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Settings\ISettings;
class Admin implements ISettings {
/**
* @return TemplateResponse
*/
public function getForm() {
return new TemplateResponse('groupfolders',
'index',
['appId' => 'groupfolders'],
'');
}
/**
* @return string the section ID, e.g. 'sharing'
*/
public function getSection() {
return 'groupfolders';
}
/**
* @return int whether the form should be rather on the top or bottom of
* the admin section. The forms are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
*
* E.g.: 70
*/
public function getPriority() {
return 90;
}
}

76
lib/Settings/Section.php Normal file
View file

@ -0,0 +1,76 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\GroupFolders\Settings;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
class Section implements IIconSection {
/** @var IL10N */
private $l;
/** @var IURLGenerator */
private $url;
public function __construct(IL10N $l, IURLGenerator $url) {
$this->l = $l;
$this->url = $url;
}
/**
* returns the ID of the section. It is supposed to be a lower case string,
* e.g. 'ldap'
*
* @returns string
*/
public function getID() {
return 'groupfolders';
}
/**
* returns the translated name as it should be displayed, e.g. 'LDAP / AD
* integration'. Use the L10N service to translate it.
*
* @return string
*/
public function getName() {
return $this->l->t('Group Folders');
}
/**
* @return int whether the form should be rather on the top or bottom of
* the settings navigation. The sections are arranged in ascending order of
* the priority values. It is required to return a value between 0 and 99.
*
* E.g.: 70
*/
public function getPriority() {
return 90;
}
/**
* {@inheritdoc}
*/
public function getIcon() {
return $this->url->imagePath('groupfolders', 'app-dark.svg');
}
}

29
package.json Normal file
View file

@ -0,0 +1,29 @@
{
"devDependencies": {
"@types/react": "^15.0.21",
"@types/react-dom": "^0.14.23",
"autoprefixer-loader": "^3.2.0",
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.0",
"eslint-plugin-react": "^6.10.3",
"extract-text-webpack-plugin": "^2.1.0",
"less": "^2.7.2",
"less-loader": "^4.0.3",
"react-hot-loader": "3.0.0-beta.6",
"style-loader": "^0.16.1",
"webpack": "^2.3.3",
"webpack-dev-server": "^2.4.2"
},
"dependencies": {
"less": "^2.7.2",
"less-loader": "^4.0.3",
"oc-react-components": "^0.2.0",
"react": "^15.4.2",
"react-dom": "^15.4.2"
}
}

4
templates/index.php Normal file
View file

@ -0,0 +1,4 @@
<?php script($_['appId'], ['../build/bundle']); ?>
<?php style($_['appId'], ['../build/bundle']); ?>
<?php style($_['appId'], ['app']); ?>
<div id="groupfolders-root"/>

49
webpack.dev.config.js Normal file
View file

@ -0,0 +1,49 @@
'use strict';
const webpack = require("webpack");
const path = require("path");
module.exports = {
devtool: 'source-map',
entry: {
app: [
'react-hot-loader/patch',
// activate HMR for React
// 'webpack-dev-server/client?http://localhost:8080',
// bundle the client for webpack-dev-server
// and connect to the provided endpoint
'webpack/hot/only-dev-server',
// bundle the client for hot reloading
// only- means to only hot reload for successful updates
'./js/index.js'
]
},
output: {
path: path.join(__dirname, "build"),
filename: "bundle.js",
publicPath: '/'
},
resolve: {
extensions: ['.js', '.jsx'],
},
plugins: [
new webpack.NamedModulesPlugin()
],
module: {
rules: [
{
test: /\.js$/,
use: ['react-hot-loader/webpack', 'babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
},
devServer: {
contentBase: path.resolve(__dirname, './src')
},
};

56
webpack.prod.config.js Normal file
View file

@ -0,0 +1,56 @@
'use strict';
const webpack = require("webpack");
const path = require("path");
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanPlugin = require('clean-webpack-plugin');
module.exports = {
devtool: 'source-map',
entry: {
app: [
`babel-polyfill`,
`whatwg-fetch`,
'./js/index.js'
],
},
output: {
path: path.join(__dirname, "build"),
filename: "bundle.js",
libraryTarget: 'umd',
publicPath: '/'
},
resolve: {
extensions: ['.js']
},
plugins: [
new CleanPlugin(['build']),
new ExtractTextPlugin({
filename: 'bundle.css',
allChunks: true
}),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
],
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ['css-loader', 'postcss-loader']
})
}
]
}
};