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