bootstrap ui framework
This commit is contained in:
parent
6b0c89b65b
commit
64a01dff71
16
ui/.babelrc
Normal file
16
ui/.babelrc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"sourceMaps": "both",
|
||||||
|
"presets": [
|
||||||
|
"react",
|
||||||
|
"es2015"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"react-hot-loader/babel",
|
||||||
|
"add-module-exports",
|
||||||
|
"transform-exponentiation-operator",
|
||||||
|
"syntax-async-functions",
|
||||||
|
["transform-object-rest-spread", {
|
||||||
|
"useBuiltIns": true
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
3
ui/.eslintignore
Normal file
3
ui/.eslintignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/node_modules
|
||||||
|
coverage
|
||||||
|
.nyc_output
|
29
ui/.eslintrc
Normal file
29
ui/.eslintrc
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"extends": "semistandard",
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 7,
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true
|
||||||
|
},
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"babel",
|
||||||
|
"react"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"generator-star-spacing": 0,
|
||||||
|
"babel/generator-star-spacing": 1,
|
||||||
|
"space-before-function-paren": [2, "never"],
|
||||||
|
"react/jsx-uses-react": 2,
|
||||||
|
"react/jsx-uses-vars": 2,
|
||||||
|
"react/react-in-jsx-scope": 2,
|
||||||
|
"object-curly-newline": ["error", {
|
||||||
|
"minProperties": 1
|
||||||
|
}],
|
||||||
|
"sort-vars": ["error", {
|
||||||
|
"ignoreCase": true
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
15
ui/.tern-project
Normal file
15
ui/.tern-project
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"libs": [
|
||||||
|
"ecmascript",
|
||||||
|
"browser"
|
||||||
|
],
|
||||||
|
"plugins": {
|
||||||
|
"doc_comment": true,
|
||||||
|
"local-scope": true,
|
||||||
|
"jsx": true,
|
||||||
|
"node": true,
|
||||||
|
"webpack": {
|
||||||
|
"configPath": "./webpack/index.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
ui/README.md
Normal file
1
ui/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Joyent Dashboard UI Framework
|
0
ui/docs/components.js
Normal file
0
ui/docs/components.js
Normal file
17
ui/docs/index.js
Normal file
17
ui/docs/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const ReactDOM = require('react-dom');
|
||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
const Root = require('./root');
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Root />,
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
if (module.hot) {
|
||||||
|
module.hot.accept('./root', render);
|
||||||
|
}
|
16
ui/docs/root.js
Normal file
16
ui/docs/root.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const ReactHotLoader = require('react-hot-loader');
|
||||||
|
const Button = require('../src/button/readme.md');
|
||||||
|
const InnerHTML = require('dangerously-set-inner-html');
|
||||||
|
|
||||||
|
const {
|
||||||
|
AppContainer
|
||||||
|
} = ReactHotLoader;
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return (
|
||||||
|
<AppContainer>
|
||||||
|
<InnerHTML html={Button} />
|
||||||
|
</AppContainer>
|
||||||
|
);
|
||||||
|
};
|
67
ui/package.json
Normal file
67
ui/package.json
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"name": "joyent-dashboard-frontend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"license": "private",
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server --open --config webpack/index.js",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"test": "NODE_ENV=test nyc ava test/*.js --verbose",
|
||||||
|
"build": "NODE_ENV=production webpack --config webpack/index.js",
|
||||||
|
"clean-static": "sh scripts/clean-static.sh",
|
||||||
|
"build-docs-static": "sh scripts/build-docs-static.sh"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^15.3.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"ava": "^0.16.0",
|
||||||
|
"babel-core": "^6.17.0",
|
||||||
|
"babel-eslint": "^7.0.0",
|
||||||
|
"babel-loader": "^6.2.5",
|
||||||
|
"babel-plugin-add-module-exports": "^0.2.1",
|
||||||
|
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||||
|
"babel-plugin-transform-object-rest-spread": "^6.16.0",
|
||||||
|
"babel-preset-es2015": "^6.16.0",
|
||||||
|
"babel-preset-react": "^6.16.0",
|
||||||
|
"babel-register": "^6.16.3",
|
||||||
|
"css-loader": "^0.25.0",
|
||||||
|
"dangerously-set-inner-html": "^1.0.0",
|
||||||
|
"enzyme": "^2.5.1",
|
||||||
|
"eslint": "^3.8.1",
|
||||||
|
"eslint-config-semistandard": "^7.0.0",
|
||||||
|
"eslint-config-standard": "^6.2.0",
|
||||||
|
"eslint-plugin-babel": "^3.3.0",
|
||||||
|
"eslint-plugin-promise": "^3.3.0",
|
||||||
|
"eslint-plugin-react": "^6.4.1",
|
||||||
|
"eslint-plugin-standard": "^2.0.1",
|
||||||
|
"extract-text-webpack-plugin": "^2.0.0-beta.4",
|
||||||
|
"html-loader": "^0.4.4",
|
||||||
|
"json-loader": "^0.5.4",
|
||||||
|
"nyc": "^8.3.1",
|
||||||
|
"postcss-cssnext": "^2.8.0",
|
||||||
|
"postcss-loader": "^1.0.0",
|
||||||
|
"pre-commit": "^1.1.3",
|
||||||
|
"react-addons-test-utils": "^15.3.2",
|
||||||
|
"react-dom": "^15.3.2",
|
||||||
|
"react-hot-loader": "^3.0.0-beta.6",
|
||||||
|
"react-router": "^4.0.0-alpha.4",
|
||||||
|
"style-loader": "^0.13.1",
|
||||||
|
"webpack": "^2.1.0-beta.25",
|
||||||
|
"webpack-dev-server": "^1.16.2",
|
||||||
|
"webpack-shell-plugin": "^0.4.3"
|
||||||
|
},
|
||||||
|
"ava": {
|
||||||
|
"failFast": true,
|
||||||
|
"cache": false,
|
||||||
|
"require": [
|
||||||
|
"babel-register"
|
||||||
|
],
|
||||||
|
"babel": "inherit"
|
||||||
|
},
|
||||||
|
"pre-commit": [
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"coverage"
|
||||||
|
]
|
||||||
|
}
|
3
ui/scripts/build-docs-static.sh
Normal file
3
ui/scripts/build-docs-static.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
echo $(pwd)
|
||||||
|
# cp -r ../static/* ../docs/static/
|
||||||
|
# mv ../docs/static/index.html ../docs/
|
0
ui/scripts/clean-static.sh
Normal file
0
ui/scripts/clean-static.sh
Normal file
5
ui/src/base/index.js
Normal file
5
ui/src/base/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return null;
|
||||||
|
};
|
16
ui/src/button/index.js
Normal file
16
ui/src/button/index.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const React = require('react');
|
||||||
|
const styles = require('./style.css');
|
||||||
|
|
||||||
|
module.exports = ({
|
||||||
|
disabled = false,
|
||||||
|
children
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={styles.button}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
29
ui/src/button/readme.md
Normal file
29
ui/src/button/readme.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# `<Button>`
|
||||||
|
|
||||||
|
## demo
|
||||||
|
|
||||||
|
```embed
|
||||||
|
const React = require('react');
|
||||||
|
const ReactDOM = require('react-dom/server');
|
||||||
|
const Button = require('./index.js');
|
||||||
|
const styles = require('./style.css');
|
||||||
|
|
||||||
|
nmodule.exports = ReactDOM.renderToString(
|
||||||
|
<Button>Hello World</Button>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
const React = require('react');
|
||||||
|
const Button = require('ui/button');
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return (
|
||||||
|
<Button disabled={false}>
|
||||||
|
Hello World
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
4
ui/src/button/style.css
Normal file
4
ui/src/button/style.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.button {
|
||||||
|
background-color: #e500ee;
|
||||||
|
margin: none;
|
||||||
|
}
|
5
ui/src/container/index.js
Normal file
5
ui/src/container/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return null;
|
||||||
|
};
|
3
ui/src/docs.js
Normal file
3
ui/src/docs.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
Button: require('./button/readme.md')
|
||||||
|
};
|
5
ui/src/index.js
Normal file
5
ui/src/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
Button: require('./button'),
|
||||||
|
Container: require('./container'),
|
||||||
|
Base: require('./base')
|
||||||
|
};
|
3
ui/static/.gitignore
vendored
Normal file
3
ui/static/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
|
!theme.css
|
72
ui/static/theme.css
Normal file
72
ui/static/theme.css
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
||||||
|
|
||||||
|
/* Tomorrow Comment */
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #8e908c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Red */
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #c82829;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Orange */
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-builtin-name,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-params,
|
||||||
|
.hljs-meta,
|
||||||
|
.hljs-link {
|
||||||
|
color: #f5871f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Yellow */
|
||||||
|
.hljs-attribute {
|
||||||
|
color: #eab700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Green */
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-addition {
|
||||||
|
color: #718c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Blue */
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-section {
|
||||||
|
color: #4271ae;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Purple */
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag {
|
||||||
|
color: #8959a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
background: white;
|
||||||
|
color: #4d4d4c;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
25
ui/test/index.js
Normal file
25
ui/test/index.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const test = require('ava');
|
||||||
|
const enzyme = require('enzyme');
|
||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
const {
|
||||||
|
shallow
|
||||||
|
} = enzyme;
|
||||||
|
|
||||||
|
test('renders <App> without exploding', (t) => {
|
||||||
|
const App = require('../src/containers/app');
|
||||||
|
const wrapper = shallow(<App />);
|
||||||
|
t.deepEqual(wrapper.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders <Home> without exploding', (t) => {
|
||||||
|
const Home = require('../src/containers/home');
|
||||||
|
const wrapper = shallow(<Home />);
|
||||||
|
t.deepEqual(wrapper.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders <NotFound> without exploding', (t) => {
|
||||||
|
const NotFound = require('../src/containers/not-found');
|
||||||
|
const wrapper = shallow(<NotFound />);
|
||||||
|
t.deepEqual(wrapper.length, 1);
|
||||||
|
});
|
76
ui/webpack/config.js
Normal file
76
ui/webpack/config.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
context: path.join(__dirname, '../'),
|
||||||
|
output: {
|
||||||
|
path: path.join(__dirname, '../static'),
|
||||||
|
publicPath: '/static/',
|
||||||
|
filename: '[name].js'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.NoErrorsPlugin(),
|
||||||
|
new ExtractTextPlugin({
|
||||||
|
filename: '[name].css',
|
||||||
|
allChunks: true
|
||||||
|
}),
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
options: {
|
||||||
|
postcss: {
|
||||||
|
plugins: () => {
|
||||||
|
return [
|
||||||
|
require('postcss-cssnext')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'embed-markdown-loader': {
|
||||||
|
// webpackConfigFullpath: path.join(__dirname, 'index.js') don't detach yet (has a bug in the production config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
resolveLoader: {
|
||||||
|
alias: {
|
||||||
|
'embed-markdown-loader': path.join(__dirname, './embed-markdown-loader')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
loaders: [{
|
||||||
|
test: /js?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
include: [
|
||||||
|
path.join(__dirname, '../src'),
|
||||||
|
path.join(__dirname, '../docs')
|
||||||
|
],
|
||||||
|
loader: 'babel'
|
||||||
|
}, {
|
||||||
|
test: /\.json?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
include: [
|
||||||
|
path.join(__dirname, '../src'),
|
||||||
|
path.join(__dirname, '../docs')
|
||||||
|
],
|
||||||
|
loader: 'json'
|
||||||
|
}, {
|
||||||
|
test: /\.md?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
include: [
|
||||||
|
path.join(__dirname, '../src'),
|
||||||
|
path.join(__dirname, '../docs')
|
||||||
|
],
|
||||||
|
loader: 'html-loader!embed-markdown-loader'
|
||||||
|
}, {
|
||||||
|
test: /\.css?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
include: [
|
||||||
|
path.join(__dirname, '../src'),
|
||||||
|
path.join(__dirname, '../docs')
|
||||||
|
],
|
||||||
|
loader: ExtractTextPlugin.extract({
|
||||||
|
fallbackLoader: 'style-loader',
|
||||||
|
loader: 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader'
|
||||||
|
})
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
35
ui/webpack/development.js
Normal file
35
ui/webpack/development.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const graphql = require('../../cloudapi-graphql/src/endpoint');
|
||||||
|
const config = require('./config.js');
|
||||||
|
const entries = require('./entrypoints');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
const devServer = {
|
||||||
|
hot: true,
|
||||||
|
compress: true,
|
||||||
|
lazy: false,
|
||||||
|
publicPath: '/static/',
|
||||||
|
setup: (app) => {
|
||||||
|
app.use('/graphql', graphql);
|
||||||
|
},
|
||||||
|
historyApiFallback: {
|
||||||
|
index: './static/index.html'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Object.assign(config, {
|
||||||
|
entry: entries.reduce((all, entry) => {
|
||||||
|
all[entry.name] = [
|
||||||
|
'react-hot-loader/patch',
|
||||||
|
'webpack-dev-server/client?http://localhost:8080',
|
||||||
|
'webpack/hot/only-dev-server',
|
||||||
|
entry.path
|
||||||
|
];
|
||||||
|
|
||||||
|
return all;
|
||||||
|
}, {}),
|
||||||
|
plugins: config.plugins.concat([
|
||||||
|
new webpack.HotModuleReplacementPlugin()
|
||||||
|
]),
|
||||||
|
devtool: 'source-map',
|
||||||
|
devServer
|
||||||
|
});
|
28
ui/webpack/embed-markdown-loader/package.json
Normal file
28
ui/webpack/embed-markdown-loader/package.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "remarkable-loader",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"async": "^2.1.2",
|
||||||
|
"clone": "^2.0.0",
|
||||||
|
"get-stdin": "^5.0.1",
|
||||||
|
"highlight.js": "^9.7.0",
|
||||||
|
"loader-utils": "^0.2.16",
|
||||||
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
"memory-fs": "^0.3.0",
|
||||||
|
"minimist": "^1.2.0",
|
||||||
|
"remarkable": "^1.7.1",
|
||||||
|
"uuid": "^2.0.3",
|
||||||
|
"webpack": "^2.1.0-beta.25"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^3.8.1",
|
||||||
|
"eslint-config-semistandard": "^7.0.0",
|
||||||
|
"eslint-config-standard": "^6.2.0",
|
||||||
|
"eslint-plugin-promise": "^3.3.0",
|
||||||
|
"eslint-plugin-standard": "^2.0.1"
|
||||||
|
}
|
||||||
|
}
|
100
ui/webpack/embed-markdown-loader/src/compile/compile.js
Normal file
100
ui/webpack/embed-markdown-loader/src/compile/compile.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
const webpack = require('webpack');
|
||||||
|
const MemoryFS = require('memory-fs');
|
||||||
|
const clone = require('lodash.clonedeep');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const getCompiler = ({
|
||||||
|
filename,
|
||||||
|
mfs,
|
||||||
|
config
|
||||||
|
}) => {
|
||||||
|
const compiler = webpack(config);
|
||||||
|
|
||||||
|
compiler.outputFileSystem = mfs;
|
||||||
|
|
||||||
|
compiler.inputFileSystem.stat = function(path, callback) {
|
||||||
|
this._statStorage.provide(path, (path, callback) => {
|
||||||
|
if (path === filename) {
|
||||||
|
return mfs.stat(path, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._stat(path, callback);
|
||||||
|
}, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
compiler.inputFileSystem.readFile = function(path, callback) {
|
||||||
|
this._readFileStorage.provide(path, (path, callback) => {
|
||||||
|
if (path === filename) {
|
||||||
|
return mfs.readFile(path, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._readFile(path, callback);
|
||||||
|
}, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
return compiler;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ({
|
||||||
|
source,
|
||||||
|
entrypoint,
|
||||||
|
config
|
||||||
|
}, fn) => {
|
||||||
|
const name = path.basename(entrypoint);
|
||||||
|
const _filename = path.resolve(config.context, entrypoint);
|
||||||
|
const _dirname = path.dirname(_filename);
|
||||||
|
|
||||||
|
const mfs = new MemoryFS();
|
||||||
|
|
||||||
|
mfs.mkdirpSync('/static');
|
||||||
|
mfs.mkdirpSync(_dirname);
|
||||||
|
mfs.writeFileSync(_filename, source);
|
||||||
|
|
||||||
|
const compiler = getCompiler({
|
||||||
|
filename: _filename,
|
||||||
|
mfs,
|
||||||
|
config: Object.assign(clone(config), {
|
||||||
|
target: 'node',
|
||||||
|
output: {
|
||||||
|
path: '/static',
|
||||||
|
filename: name
|
||||||
|
},
|
||||||
|
entry: [
|
||||||
|
`./${path.relative(config.context, _filename)}`
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
compiler.run((err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
return fn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errors = stats.toJson().errors;
|
||||||
|
|
||||||
|
if (errors && errors.length) {
|
||||||
|
return fn(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
mfs.readFile(`/static/${name}`, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return fn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let style = mfs.readdirSync('/static').filter((file) => {
|
||||||
|
return /\.css$/.test(file);
|
||||||
|
}).map((file) => {
|
||||||
|
try {
|
||||||
|
return mfs.readFileSync(`/static/${file}`, 'utf-8');
|
||||||
|
} catch (err) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}).concat('\n');
|
||||||
|
|
||||||
|
fn(err, {
|
||||||
|
body: (res && res.toString) ? res.toString() : res,
|
||||||
|
style
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
51
ui/webpack/embed-markdown-loader/src/compile/detach.js
Normal file
51
ui/webpack/embed-markdown-loader/src/compile/detach.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
const spawn = require('child_process').spawn;
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const executable = path.join(__dirname, 'detached.js');
|
||||||
|
|
||||||
|
module.exports = ({
|
||||||
|
source,
|
||||||
|
entrypoint,
|
||||||
|
configFullpath
|
||||||
|
}, fn) => {
|
||||||
|
let out = '';
|
||||||
|
let err = '';
|
||||||
|
|
||||||
|
const child = spawn('node', [
|
||||||
|
executable,
|
||||||
|
`--entrypoint=${entrypoint}`,
|
||||||
|
`--config=${configFullpath}`
|
||||||
|
]);
|
||||||
|
|
||||||
|
child.stdin.write(source);
|
||||||
|
child.stdin.end();
|
||||||
|
|
||||||
|
child.stdout.on('data', (data) => {
|
||||||
|
out += data;
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stderr.on('data', (data) => {
|
||||||
|
err += data;
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('close', (code) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
return fn(new Error(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
style: '',
|
||||||
|
body: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const _res = JSON.parse(out);
|
||||||
|
res.style = _res.style;
|
||||||
|
res.body = _res.body;
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(null, res);
|
||||||
|
});
|
||||||
|
};
|
25
ui/webpack/embed-markdown-loader/src/compile/detached.js
Normal file
25
ui/webpack/embed-markdown-loader/src/compile/detached.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const argv = require('minimist')(process.argv.slice(2));
|
||||||
|
const getStdin = require('get-stdin');
|
||||||
|
|
||||||
|
const compile = require('./compile');
|
||||||
|
|
||||||
|
const {
|
||||||
|
entrypoint,
|
||||||
|
config
|
||||||
|
} = argv;
|
||||||
|
|
||||||
|
const webpackConfig = require(config);
|
||||||
|
|
||||||
|
getStdin().then((source) => {
|
||||||
|
compile({
|
||||||
|
source,
|
||||||
|
entrypoint,
|
||||||
|
config: webpackConfig
|
||||||
|
}, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(res));
|
||||||
|
});
|
||||||
|
});
|
18
ui/webpack/embed-markdown-loader/src/compile/index.js
Normal file
18
ui/webpack/embed-markdown-loader/src/compile/index.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const compile = require('./compile');
|
||||||
|
const detach = require('./detach');
|
||||||
|
|
||||||
|
module.exports = ({
|
||||||
|
source,
|
||||||
|
entrypoint,
|
||||||
|
config
|
||||||
|
}, fn) => {
|
||||||
|
return !config.fullpath ? compile({
|
||||||
|
source,
|
||||||
|
entrypoint,
|
||||||
|
config: config.instantiated
|
||||||
|
}, fn) : detach({
|
||||||
|
source,
|
||||||
|
entrypoint,
|
||||||
|
configFullpath: config.fullpath
|
||||||
|
}, fn);
|
||||||
|
};
|
29
ui/webpack/embed-markdown-loader/src/eval.js
Normal file
29
ui/webpack/embed-markdown-loader/src/eval.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const Module = require('module');
|
||||||
|
const vm = require('vm');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = ({
|
||||||
|
source,
|
||||||
|
entrypoint
|
||||||
|
}) => {
|
||||||
|
const script = vm.createScript(source, entrypoint);
|
||||||
|
const dirname = path.basename(entrypoint);
|
||||||
|
const rootName = path.join(dirname, '@root');
|
||||||
|
|
||||||
|
const _module = new Module(rootName);
|
||||||
|
|
||||||
|
_module.filename = rootName;
|
||||||
|
_module.paths = Module._nodeModulePaths(dirname);
|
||||||
|
|
||||||
|
script.runInNewContext({
|
||||||
|
nmodule: _module,
|
||||||
|
nrequire: _module.require,
|
||||||
|
__filename: entrypoint,
|
||||||
|
__dirname: dirname,
|
||||||
|
process,
|
||||||
|
console,
|
||||||
|
Buffer
|
||||||
|
});
|
||||||
|
|
||||||
|
return _module.exports;
|
||||||
|
};
|
15
ui/webpack/embed-markdown-loader/src/highlight.js
Normal file
15
ui/webpack/embed-markdown-loader/src/highlight.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const hljs = require('highlight.js');
|
||||||
|
|
||||||
|
module.exports = (str, lang) => {
|
||||||
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
|
try {
|
||||||
|
return hljs.highlight(lang, str).value;
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return hljs.highlightAuto(str).value;
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
28
ui/webpack/embed-markdown-loader/src/index.js
Normal file
28
ui/webpack/embed-markdown-loader/src/index.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const loaderUtils = require('loader-utils');
|
||||||
|
const parse = require('./parse');
|
||||||
|
const hl = require('./highlight');
|
||||||
|
|
||||||
|
module.exports = function(source) {
|
||||||
|
const fn = this.async();
|
||||||
|
|
||||||
|
const config = loaderUtils.getLoaderConfig(this, 'embed-markdown-loader');
|
||||||
|
const fullname = loaderUtils.getRemainingRequest(this);
|
||||||
|
const mode = config.mode || 'shadow';
|
||||||
|
|
||||||
|
parse({
|
||||||
|
mode,
|
||||||
|
fullname,
|
||||||
|
source,
|
||||||
|
config: {
|
||||||
|
webpack: {
|
||||||
|
instantiated: this._compilation.options,
|
||||||
|
fullpath: config.webpackConfigFullpath
|
||||||
|
},
|
||||||
|
renderer: {
|
||||||
|
html: true,
|
||||||
|
breaks: true,
|
||||||
|
highlight: hl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, fn);
|
||||||
|
};
|
98
ui/webpack/embed-markdown-loader/src/parse.js
Normal file
98
ui/webpack/embed-markdown-loader/src/parse.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
const async = require('async');
|
||||||
|
const Remarkable = require('remarkable');
|
||||||
|
const compile = require('./compile');
|
||||||
|
const evaluate = require('./eval');
|
||||||
|
const uuid = require('uuid').v4;
|
||||||
|
|
||||||
|
const templates = {
|
||||||
|
plain: (style, body) => `
|
||||||
|
<style>${style}</style>
|
||||||
|
${body}
|
||||||
|
`,
|
||||||
|
iframe: (style, body) => {
|
||||||
|
const _body = body.replace(/"/g, '\'');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<iframe srcdoc="
|
||||||
|
<html>
|
||||||
|
<style>${style}</style>
|
||||||
|
<body>${_body}</body>">
|
||||||
|
</iframe>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
shadow: (style, body) => {
|
||||||
|
const id = uuid();
|
||||||
|
const script = `(function() {
|
||||||
|
const element = document.getElementById('${id}').attachShadow({
|
||||||
|
mode: 'closed'
|
||||||
|
});
|
||||||
|
|
||||||
|
const template = document.getElementById('${id}-template');
|
||||||
|
element.appendChild(document.importNode(template.content, true));
|
||||||
|
})();`;
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div id="${id}"></div>
|
||||||
|
<template id="${id}-template">
|
||||||
|
${templates.plain(style, body)}
|
||||||
|
</template>
|
||||||
|
<script>${script}</script>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = ({
|
||||||
|
mode = 'shadow',
|
||||||
|
fullname,
|
||||||
|
source,
|
||||||
|
config = {}
|
||||||
|
}, fn) => {
|
||||||
|
const instance = new Remarkable(config.renderer);
|
||||||
|
|
||||||
|
const {
|
||||||
|
parse,
|
||||||
|
renderer,
|
||||||
|
options
|
||||||
|
} = instance;
|
||||||
|
|
||||||
|
const entrypoint = fullname.replace(/\.md$/, '.js');
|
||||||
|
const tokens = parse.call(instance, source, options, {});
|
||||||
|
|
||||||
|
async.map(tokens, (token, fn) => {
|
||||||
|
if ((token.type !== 'fence') || (token.params !== 'embed')) {
|
||||||
|
return fn(null, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
compile({
|
||||||
|
source: token.content,
|
||||||
|
config: config.webpack,
|
||||||
|
entrypoint
|
||||||
|
}, (err, {
|
||||||
|
body,
|
||||||
|
style
|
||||||
|
}) => {
|
||||||
|
if (err) {
|
||||||
|
return fn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const evaluated = evaluate({
|
||||||
|
entrypoint,
|
||||||
|
source: body
|
||||||
|
});
|
||||||
|
|
||||||
|
const content = templates[mode](style, evaluated);
|
||||||
|
|
||||||
|
return fn(null, {
|
||||||
|
type: 'htmlblock',
|
||||||
|
content
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, (err, tokens) => {
|
||||||
|
if (err) {
|
||||||
|
return fn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(err, renderer.render.call(instance.renderer, tokens, options, {}));
|
||||||
|
});
|
||||||
|
};
|
21
ui/webpack/entrypoints.js
Normal file
21
ui/webpack/entrypoints.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const docs = path.join(__dirname, '../docs/index');
|
||||||
|
const src = path.join(__dirname, '../src/');
|
||||||
|
const ui = path.join(src, './index.js');
|
||||||
|
|
||||||
|
module.exports = fs
|
||||||
|
.readdirSync(src)
|
||||||
|
.filter((entry) => fs.statSync(path.join(src, entry)).isDirectory())
|
||||||
|
.map((entry) => ({
|
||||||
|
name: entry,
|
||||||
|
path: path.join(src, entry, './index.js')
|
||||||
|
}))
|
||||||
|
.concat([{
|
||||||
|
name: 'docs',
|
||||||
|
path: docs
|
||||||
|
}, {
|
||||||
|
name: 'ui',
|
||||||
|
path: ui
|
||||||
|
}]);
|
2
ui/webpack/index.js
Normal file
2
ui/webpack/index.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const NODE_ENV = process.env['NODE_ENV'] || 'development';
|
||||||
|
module.exports = require(`./${NODE_ENV}`);
|
31
ui/webpack/production.js
Normal file
31
ui/webpack/production.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const WebpackShellPlugin = require('webpack-shell-plugin');
|
||||||
|
const config = require('./config.js');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const entries = require('./entrypoints');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = Object.assign(config, {
|
||||||
|
entry: entries.reduce((all, entry) => {
|
||||||
|
all[entry.name] = [entry.path];
|
||||||
|
return all;
|
||||||
|
}, {}),
|
||||||
|
plugins: config.plugins.concat([
|
||||||
|
new webpack.optimize.DedupePlugin(),
|
||||||
|
new webpack.optimize.OccurrenceOrderPlugin(true),
|
||||||
|
new webpack.optimize.UglifyJsPlugin(),
|
||||||
|
new WebpackShellPlugin({
|
||||||
|
onBuildEnd: [
|
||||||
|
'npm run build-docs-static'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
devtool: 'eval'
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maybe add in the future:
|
||||||
|
* - https://github.com/lettertwo/appcache-webpack-plugin
|
||||||
|
* - https://github.com/NekR/offline-plugin
|
||||||
|
* - https://github.com/goldhand/sw-precache-webpack-plugin
|
||||||
|
* - https://github.com/Klathmon/imagemin-webpack-plugin
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user