├── .gitignore
├── test
├── .eslintrc
├── index.js
└── src
│ └── components
│ └── app
│ └── index.js
├── docs
└── screenshot.png
├── src
├── index.js
├── theme-bootstrap
│ ├── form
│ │ ├── styles.less
│ │ └── index.js
│ ├── app
│ │ ├── styles.less
│ │ └── index.js
│ ├── index.js
│ ├── link
│ │ └── styles.less
│ ├── notification
│ │ ├── index.js
│ │ └── styles.less
│ ├── heading
│ │ ├── index.js
│ │ └── styles.less
│ ├── input
│ │ └── styles.less
│ └── button
│ │ └── styles.less
├── assets
│ └── index.html
└── components
│ ├── app
│ ├── styles.less
│ └── index.js
│ └── authentication
│ ├── styles.less
│ └── index.js
├── .eslintrc
├── conf
├── karma.build.js
├── karma.dev.js
├── webpack.dev.js
├── karma.common.js
├── webpack.build.js
├── webpack.common.js
└── webpack.test.js
├── .babelrc
├── .editorconfig
├── .travis.yml
├── license.md
├── tasks.js
├── readme.md
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | build/
3 | coverage/
4 | *.log
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "rebem/configs/test"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/docs/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rebem/starter-kit/HEAD/docs/screenshot.png
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { render } from 'react-dom';
2 | import App from '#app';
3 |
4 | render(App(), document.getElementById('app'));
5 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "rebem/configs/common",
4 | "rebem/configs/babel",
5 | "rebem/configs/react"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/conf/karma.build.js:
--------------------------------------------------------------------------------
1 | import karmaCommonConfig from './karma.common';
2 |
3 | export default {
4 | ...karmaCommonConfig,
5 | singleRun: true,
6 | autoWatch: false
7 | };
8 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/form/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 | @import '~bootstrap/less/mixins/forms';
3 | @import '~bootstrap/less/mixins/vendor-prefixes';
4 |
5 | .form {
6 | }
7 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "es2015", "stage-1" ],
3 | "plugins": [ "transform-runtime" ],
4 | "env": {
5 | "development": {
6 | "presets": [ "react-hmre" ]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/app/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 |
3 | body {
4 | font-family: @font-family-base;
5 | font-size: @font-size-base;
6 | line-height: @line-height-base;
7 | }
8 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/app/index.js:
--------------------------------------------------------------------------------
1 | import { BEM } from 'rebem';
2 |
3 | export default function App({ children, ...props }) {
4 | return BEM({
5 | ...props,
6 | block: 'app'
7 | }, children);
8 | }
9 |
--------------------------------------------------------------------------------
/src/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/form/index.js:
--------------------------------------------------------------------------------
1 | import { BEM } from 'rebem';
2 |
3 | export default function({ children, ...props }) {
4 | return BEM({
5 | ...props,
6 | block: 'form',
7 | tag: 'form'
8 | }, children);
9 | }
10 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/index.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | module.exports = {
4 | path: path.resolve(__dirname, './'),
5 | files: {
6 | main: 'index.js',
7 | styles: 'styles.less'
8 | },
9 | importFactory: true
10 | };
11 |
--------------------------------------------------------------------------------
/conf/karma.dev.js:
--------------------------------------------------------------------------------
1 | import karmaCommonConfig from './karma.common';
2 |
3 | export default {
4 | ...karmaCommonConfig,
5 | singleRun: false,
6 | autoWatch: true,
7 | reporters: [
8 | 'clear-screen',
9 | ...karmaCommonConfig.reporters
10 | ]
11 | };
12 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/link/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 |
3 | @link-color: @brand-primary;
4 | @link-hover-color: darken(@link-color, 15%);
5 |
6 | .link {
7 | color: @link-color;
8 |
9 | &:hover {
10 | color: @link-hover-color;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org/
2 | root = true
3 |
4 | [*]
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | charset = utf-8
9 | indent_style = space
10 | indent_size = 4
11 |
12 | [*.{json,yml}]
13 | indent_size = 2
14 |
15 | [{.babelrc,.eslintrc}]
16 | indent_size = 2
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # https://docs.travis-ci.com/user/customizing-the-build/
2 |
3 | sudo: false
4 |
5 | git:
6 | depth: 1
7 |
8 | language: node_js
9 |
10 | node_js:
11 | # - "0.12"
12 | - "4"
13 | - "5"
14 |
15 | branches:
16 | only:
17 | - master
18 |
19 | matrix:
20 | fast_finish: true
21 |
22 | before_install:
23 | - npm install -g npm
24 | - npm --version
25 |
26 | script: npm start test
27 |
--------------------------------------------------------------------------------
/src/components/app/styles.less:
--------------------------------------------------------------------------------
1 | .app {
2 | display: flex;
3 | min-height: 100vh;
4 | flex-direction: column;
5 |
6 | &__header {
7 | padding: 20px;
8 | color: #fff;
9 | background: #337ab7;
10 | }
11 |
12 | &__content {
13 | padding: 40px 20px;
14 | flex: 1;
15 | }
16 |
17 | &__footer {
18 | background: #ddd;
19 | padding: 20px;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/authentication/styles.less:
--------------------------------------------------------------------------------
1 | .authentication {
2 | position: relative;
3 | padding: 25px 0 15px;
4 | margin: 0 -15px 15px;
5 | border-radius: 4px;
6 | border: 1px solid #ddd;
7 | width: 400px;
8 | margin: auto;
9 |
10 | &__heading {
11 | margin: 0 20px 20px;
12 | }
13 |
14 | &__status {
15 | margin: 20px;
16 |
17 | &_empty {
18 | display: none;
19 | }
20 | }
21 |
22 | &__form-row {
23 | margin-top: 15px;
24 | padding: 0 15px;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/notification/index.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'react';
2 | import { BEM } from 'rebem';
3 |
4 | export default function Notification({ children, ...props }) {
5 | return BEM({
6 | ...props,
7 | block: 'notification',
8 | mods: {
9 | ...props.mods,
10 | type: props.type || false
11 | }
12 | }, children);
13 | }
14 |
15 | Notification.propTypes = {
16 | type: PropTypes.oneOf([
17 | 'success',
18 | 'info',
19 | 'warning',
20 | 'error'
21 | ])
22 | };
23 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/heading/index.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'react';
2 | import { BEM } from 'rebem';
3 |
4 | export default function Heading({ children, type, ...props }) {
5 | return BEM({
6 | ...props,
7 | tag: type,
8 | block: 'heading',
9 | mods: {
10 | ...props.mods,
11 | type
12 | }
13 | }, children);
14 | }
15 |
16 | Heading.defaultProps = {
17 | type: 'h1'
18 | };
19 |
20 | Heading.propTypes = {
21 | type: PropTypes.oneOf([
22 | 'h1',
23 | 'h2',
24 | 'h3',
25 | 'h4',
26 | 'h5',
27 | 'h6'
28 | ])
29 | };
30 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/notification/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 |
3 | .notification {
4 | padding: 20px;
5 | border: 1px solid #eee;
6 | border-left-width: 5px;
7 | border-left-color: @brand-primary;
8 | border-radius: 3px;
9 |
10 | &_type {
11 | &_success {
12 | border-left-color: @brand-success;
13 | }
14 |
15 | &_info {
16 | border-left-color: @brand-info;
17 | }
18 |
19 | &_error {
20 | border-left-color: @brand-danger;
21 | }
22 |
23 | &_warning {
24 | border-left-color: @brand-warning;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/heading/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 |
3 | .heading {
4 | line-height: @headings-line-height;
5 | font-weight: normal;
6 |
7 | &_type {
8 | &_h1 {
9 | font-size: @font-size-h1;
10 | }
11 |
12 | &_h2 {
13 | font-size: @font-size-h2;
14 | }
15 |
16 | &_h3 {
17 | font-size: @font-size-h3;
18 | }
19 |
20 | &_h4 {
21 | font-size: @font-size-h4;
22 | }
23 |
24 | &_h5 {
25 | font-size: @font-size-h5;
26 | }
27 |
28 | &_h6 {
29 | font-size: @font-size-h6;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/input/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 | @import '~bootstrap/less/mixins/forms';
3 | @import '~bootstrap/less/mixins/vendor-prefixes';
4 |
5 | .input {
6 | display: block;
7 | width: 100%;
8 |
9 | &__control {
10 | height: @input-height-base;
11 | padding: @padding-base-vertical @padding-base-horizontal;
12 | font-size: @font-size-base;
13 | line-height: @line-height-base;
14 | color: @input-color;
15 | background-color: @input-bg;
16 | border: 1px solid @input-border;
17 | border-radius: @input-border-radius;
18 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
19 | .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s");
20 | .placeholder();
21 | .form-control-focus();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/app/index.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { blockFactory } from 'rebem';
3 |
4 | import App from '#app';
5 | import Authentication from '#authentication';
6 | import Heading from '#heading';
7 | import Link from '#link';
8 |
9 | const block = 'app';
10 | const Block = blockFactory(block);
11 |
12 | export default class extends Component {
13 | render() {
14 | return App(this.props,
15 | Block({ elem: 'header' },
16 | Heading({
17 | mix: { block, elem: 'title' }
18 | }, 'reBEM Starter Kit')
19 | ),
20 | Block({ elem: 'content' },
21 | Authentication()
22 | ),
23 | Block({ elem: 'footer' },
24 | 'Made with ',
25 | Link({ href: 'http://rebem.js.org/' }, 'reBEM')
26 | )
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai';
2 | import chaiBEM from 'chai-bem';
3 | import chaiSpies from 'chai-spies';
4 | import chaiEnzyme from 'chai-enzyme';
5 |
6 | import { ShallowWrapper, ReactWrapper } from 'enzyme';
7 |
8 | chai.use(chaiBEM({
9 | entityHook(entity) {
10 | if (entity instanceof ShallowWrapper || entity instanceof ReactWrapper) {
11 | return entity.prop('className');
12 | }
13 |
14 | return entity;
15 | }
16 | }));
17 | chai.use(chaiSpies);
18 | chai.use(chaiEnzyme(({ wrapper }) => wrapper.debug()));
19 |
20 | // https://github.com/webpack/karma-webpack#alternative-usage
21 |
22 | // components
23 | const componentsTests = require.context('./src/components/', true, /\.js$/);
24 | const componentsSources = require.context('../src/components/', true, /\.js$/);
25 |
26 | componentsTests.keys().forEach(componentsTests);
27 | componentsSources.keys().forEach(componentsSources);
28 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | * Copyright (c) 2015–present Kir Belevich
4 | * Copyright (c) 2015–present Denis Koltsov
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/src/theme-bootstrap/button/styles.less:
--------------------------------------------------------------------------------
1 | @import '~bootstrap/less/variables';
2 | @import '~bootstrap/less/pagination';
3 | @import '~bootstrap/less/mixins/border-radius';
4 | @import '~bootstrap/less/mixins/buttons';
5 | @import '~bootstrap/less/mixins/pagination';
6 | @import '~bootstrap/less/mixins/tab-focus';
7 | @import '~bootstrap/less/mixins/vendor-prefixes';
8 |
9 | .button {
10 | &__control {
11 | margin-bottom: 0;
12 | font-weight: @btn-font-weight;
13 | text-align: center;
14 | vertical-align: middle;
15 | border: 1px solid transparent;
16 | .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);
17 |
18 | &,
19 | &:active,
20 | &.active {
21 | &:focus,
22 | &.focus {
23 | .tab-focus();
24 | }
25 | }
26 |
27 | &:hover,
28 | &:focus,
29 | &.focus {
30 | color: @btn-default-color;
31 | text-decoration: none;
32 | }
33 |
34 | &:active,
35 | &.active {
36 | outline: 0;
37 | background-image: none;
38 | .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
39 | }
40 | .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/conf/webpack.dev.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import webpack from 'webpack';
3 |
4 | import webpackCommonConfig from './webpack.common';
5 |
6 | export default {
7 | ...webpackCommonConfig,
8 | entry: [
9 | 'webpack/hot/dev-server',
10 | './src/index'
11 | ],
12 | output: {
13 | ...webpackCommonConfig.output,
14 | path: path.resolve('./'),
15 | publicPath: '/',
16 | filename: 'bundle.js'
17 | },
18 | // devtool: '#cheap-module-eval-source-map',
19 | module: {
20 | preLoaders: webpackCommonConfig.module.preLoaders,
21 | loaders: [
22 | ...webpackCommonConfig.module.loaders,
23 | {
24 | test: /\.css$/,
25 | loaders: [
26 | 'style',
27 | 'css?-minimize',
28 | 'postcss'
29 | ]
30 | },
31 | {
32 | test: /\.less$/,
33 | loaders: [
34 | 'style',
35 | 'css?-minimize',
36 | 'postcss',
37 | 'less'
38 | ]
39 | }
40 | ]
41 | },
42 | plugins: [
43 | ...webpackCommonConfig.plugins,
44 | new webpack.HotModuleReplacementPlugin(),
45 | new webpack.NoErrorsPlugin()
46 | ]
47 | };
48 |
--------------------------------------------------------------------------------
/tasks.js:
--------------------------------------------------------------------------------
1 | import Start from 'start';
2 | import reporter from 'start-pretty-reporter';
3 | import env from 'start-env';
4 | import files from 'start-files';
5 | import clean from 'start-clean';
6 | import eslint from 'start-eslint';
7 | import * as webpack from 'start-webpack';
8 | import karma from 'start-karma';
9 |
10 | const start = Start(reporter());
11 |
12 | export function build() {
13 | return start(
14 | env('production'),
15 | files('build/'),
16 | clean(),
17 | webpack.build(require('./conf/webpack.build').default)
18 | );
19 | }
20 |
21 | export function dev() {
22 | return start(
23 | env('development'),
24 | webpack.dev(require('./conf/webpack.dev').default)
25 | );
26 | }
27 |
28 | export function lint() {
29 | return start(
30 | env('test'),
31 | files([ 'src/**/*.js', 'test/**/*.js', 'conf/**/*.js' ]),
32 | eslint()
33 | );
34 | }
35 |
36 | export function test() {
37 | return start(
38 | env('test'),
39 | lint,
40 | files('coverage/'),
41 | clean(),
42 | karma(require('./conf/karma.build').default)
43 | );
44 | }
45 |
46 | export function tdd() {
47 | return start(
48 | env('test'),
49 | files('coverage/'),
50 | clean(),
51 | karma(require('./conf/karma.dev').default)
52 | );
53 | }
54 |
55 | export const prepush = test;
56 |
--------------------------------------------------------------------------------
/conf/karma.common.js:
--------------------------------------------------------------------------------
1 | import { LOG_WARN } from 'karma/lib/constants';
2 |
3 | import webpackTestConfig from './webpack.test';
4 |
5 | export default {
6 | port: 3001,
7 | webpackPort: 3002,
8 | colors: true,
9 | basePath: './',
10 | files: [
11 | 'test/index.js'
12 | ],
13 | // https://npmjs.org/browse/keyword/karma-preprocessor
14 | preprocessors: {
15 | 'test/index.js': 'webpack'
16 | },
17 | // https://npmjs.org/browse/keyword/karma-adapter
18 | frameworks: [ 'mocha' ],
19 | webpack: webpackTestConfig,
20 | webpackMiddleware: {
21 | noInfo: true,
22 | quiet: true
23 | },
24 | // https://npmjs.org/browse/keyword/karma-reporter
25 | reporters: [ 'mocha', 'coverage' ],
26 | // https://github.com/karma-runner/karma-coverage/blob/master/docs/configuration.md
27 | coverageReporter: {
28 | dir: 'coverage/',
29 | reporters: [
30 | {
31 | type: 'html'
32 | },
33 | {
34 | type: 'text-summary'
35 | },
36 | {
37 | type: 'lcovonly', subdir: '.'
38 | }
39 | ]
40 | },
41 | logLevel: LOG_WARN,
42 | browsers: [ 'jsdom' ],
43 | browserNoActivityTimeout: 30000, // default 10 * 1000
44 | browserDisconnectTimeout: 10000, // default 2 * 1000
45 | browserDisconnectTolerance: 1 // default 0
46 | };
47 |
--------------------------------------------------------------------------------
/conf/webpack.build.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import webpack from 'webpack';
3 | import ExtractTextPlugin from 'extract-text-webpack-plugin';
4 |
5 | import webpackCommonConfig from './webpack.common';
6 |
7 | export default {
8 | ...webpackCommonConfig,
9 | entry: {
10 | vendor: [
11 | 'react',
12 | 'react-dom',
13 | 'rebem',
14 | 'rebem-core-components',
15 | 'rebem-theme-reset'
16 | ],
17 | app: './src/index'
18 | },
19 | output: {
20 | path: path.resolve('./build/'),
21 | filename: 'js/[name].js'
22 | },
23 | module: {
24 | preLoaders: webpackCommonConfig.module.preLoaders,
25 | loaders: [
26 | ...webpackCommonConfig.module.loaders,
27 | {
28 | test: /\.css$/,
29 | loader: ExtractTextPlugin.extract(
30 | 'style',
31 | 'css?-minimize' +
32 | '!postcss'
33 | )
34 | },
35 | {
36 | test: /\.less$/,
37 | loader: ExtractTextPlugin.extract(
38 | 'style',
39 | 'css?-minimize' +
40 | '!postcss' +
41 | '!less'
42 | )
43 | }
44 | ]
45 | },
46 | plugins: [
47 | ...webpackCommonConfig.plugins,
48 | new webpack.optimize.CommonsChunkPlugin('vendor', 'js/[name].js'),
49 | new ExtractTextPlugin('css/[name].css', {
50 | allChunks: true
51 | }),
52 | new webpack.optimize.DedupePlugin(),
53 | new webpack.optimize.OccurenceOrderPlugin()
54 | ]
55 | };
56 |
--------------------------------------------------------------------------------
/src/components/authentication/index.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 | import { blockFactory } from 'rebem';
3 |
4 | import Button from '#button';
5 | import Form from '#form';
6 | import Heading from '#heading';
7 | import Input from '#input';
8 | import Notification from '#notification';
9 |
10 | const block = 'authentication';
11 | const Block = blockFactory(block);
12 |
13 | export default class Authentication extends Component {
14 | constructor(props) {
15 | super(props);
16 |
17 | this.state = {
18 | status: ''
19 | };
20 | }
21 |
22 | handleFormSubmit = e => {
23 | e.preventDefault();
24 |
25 | this.setState({
26 | status: 'ready to go!'
27 | });
28 | };
29 |
30 | render() {
31 | return Block(this.props,
32 | Heading({
33 | type: 'h2',
34 | mix: {
35 | block,
36 | elem: 'heading'
37 | }
38 | }, 'Login'),
39 | Notification({
40 | mix: {
41 | block,
42 | elem: 'status',
43 | mods: { empty: this.state.status === '' }
44 | }
45 | }, this.state.status),
46 | Form({ mix: { block, elem: 'form' }, onSubmit: this.handleFormSubmit },
47 | Block({ elem: 'form-row' },
48 | Input({ placeholder: 'login' })
49 | ),
50 | Block({ elem: 'form-row' },
51 | Input({ placeholder: 'password', type: 'password' })
52 | ),
53 | Block({ elem: 'form-row' },
54 | Button({ type: 'submit', value: 'Submit' })
55 | )
56 | )
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/test/src/components/app/index.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { shallow } from 'rebem-enzyme';
3 |
4 | import App from '#app';
5 |
6 | // we import factory by default, but in tests we need class
7 | import Authentication from '#authentication?class';
8 | import Heading from '#heading?class';
9 |
10 | let renderedComponent = null;
11 | const block = 'app';
12 |
13 | describe('App', function() {
14 | it('should exist', function() {
15 | expect(App).to.exist;
16 | });
17 |
18 | describe('render', function() {
19 | beforeEach(function() {
20 | renderedComponent = shallow(App());
21 | });
22 |
23 | describe('header elem', function() {
24 | let headerElement = null;
25 |
26 | beforeEach(function() {
27 | headerElement = renderedComponent.findBEM({ block, elem: 'header' });
28 | });
29 |
30 | it('exists', function() {
31 | expect(headerElement).to.have.length(1);
32 | });
33 |
34 | it('Heading component', function() {
35 | expect(headerElement.find(Heading)).to.have.length(1);
36 | });
37 | });
38 |
39 | describe('content elem', function() {
40 | let contentElement = null;
41 |
42 | beforeEach(function() {
43 | contentElement = renderedComponent.findBEM({ block, elem: 'content' });
44 | });
45 |
46 | it('exists', function() {
47 | expect(contentElement).to.have.length(1);
48 | });
49 |
50 | it('Authentication component', function() {
51 | expect(contentElement.find(Authentication)).to.have.length(1);
52 | });
53 | });
54 |
55 | it('footer elem', function() {
56 | expect(renderedComponent.findBEM({ block, elem: 'footer' })).to.have.length(1);
57 | });
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # reBEM Starter Kit
2 |
3 | [](http://unmaintained.tech)
4 | [](https://travis-ci.org/rebem/starter-kit)
5 | [](https://gemnasium.com/rebem/starter-kit)
6 |
7 | React starter kit based on [reBEM](https://github.com/rebem) stack.
8 |
9 |
10 |
11 | ## Structure
12 |
13 | * `build/` – output folder
14 | * `conf/` – configs
15 | * `tasks.js` – [start](https://github.com/start-runner/start) tasks
16 | * `src/index.js` – main entry point
17 | * `src/components` – app [layer](#layers) components
18 | * `src/theme-bootstrap` – bootstrap [layer](#layers) components
19 | * `test` — tests
20 |
21 | ## Usage
22 |
23 | ### install
24 |
25 | ```
26 | npm i
27 | ```
28 |
29 | ### dev
30 |
31 | ```
32 | npm start dev
33 | open http://localhost:3000/webpack-dev-server/
34 | ```
35 |
36 | ### build
37 |
38 | ```
39 | npm start build
40 | open build/index.html
41 | ```
42 |
43 | ### Layers
44 |
45 | There are four [reBEM layers](https://github.com/rebem/layers-loader) in this starter kit:
46 |
47 | 1. [reBEM core components](https://github.com/rebem/core-components)
48 | 2. [reBEM reset theme](https://github.com/rebem/theme-reset)
49 | 3. Simple inline theme based on [Bootstrap 3](https://github.com/twbs/bootstrap). It'll give you the basic understanding on how to create your own themes.
50 | 4. App itself
51 |
52 | Feel free to create and use your own.
53 |
54 | ## Testing
55 |
56 | Tests are preconfigured with [karma](https://karma-runner.github.io/0.13/index.html), [mocha](https://mochajs.org/) and [chai](http://chaijs.com/). Testing stack also includes some useful helpers:
57 | - [enzyme](https://github.com/airbnb/enzyme) — great testing library for React
58 | - [rebem-enzyme](https://github.com/rebem/enzyme) — BEM addons for Enzyme
59 | - [chai-bem](https://github.com/mistadikay/chai-bem) — Chai assertions for BEM class names
60 |
61 | ### run tests in TDD mode
62 |
63 | ```
64 | npm start tdd
65 | ```
66 |
67 | ### run tests once
68 |
69 | ```
70 | npm start test
71 | ```
72 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rebem-starter-kit",
3 | "version": "0.0.0",
4 | "description": "reBEM Starter Kit",
5 | "homepage": "https://github.com/rebem/starter-kit",
6 | "repository": "rebem/starter-kit",
7 | "maintainers": [
8 | "Kir Belevich (https://github.com/deepsweet)",
9 | "Denis Koltsov (https://github.com/mistadikay)"
10 | ],
11 | "dependencies": {
12 | "webpack": "1.12.x",
13 | "style-loader": "0.13.x",
14 | "css-loader": "0.23.x",
15 | "postcss-loader": "0.8.x",
16 | "autoprefixer": "6.3.x",
17 | "less": "2.6.x",
18 | "less-loader": "2.2.x",
19 | "json-loader": "0.5.x",
20 | "extract-text-webpack-plugin": "1.0.x",
21 | "html-webpack-plugin": "2.15.x",
22 |
23 | "babel-preset-es2015": "6.6.x",
24 | "babel-preset-stage-1": "6.5.x",
25 | "babel-plugin-transform-runtime": "6.6.x",
26 | "babel-loader": "6.2.x",
27 |
28 | "bootstrap": "3.3.6",
29 |
30 | "react": "0.14.x",
31 | "react-dom": "0.14.x",
32 | "rebem": "0.9.x",
33 | "rebem-layers-loader": "0.5.x",
34 | "rebem-core-components": "0.3.x",
35 | "rebem-theme-reset": "0.2.x"
36 | },
37 | "devDependencies": {
38 | "start": "4.x.x",
39 | "start-babel-cli": "1.x.x",
40 | "start-pretty-reporter": "0.x.x",
41 | "start-env": "0.x.x",
42 | "start-files": "0.x.x",
43 | "start-clean": "1.x.x",
44 | "start-eslint": "2.x.x",
45 | "start-webpack": "0.x.x",
46 | "start-karma": "0.x.x",
47 |
48 | "babel-eslint": "6.0.x",
49 | "eslint-plugin-babel": "3.1.x",
50 | "eslint-plugin-react": "4.2.x",
51 | "eslint-config-rebem": "1.1.x",
52 | "babel-preset-react-hmre": "1.1.x",
53 |
54 | "enzyme": "2.2.x",
55 | "chai-enzyme": "0.4.x",
56 | "rebem-enzyme": "0.3.x",
57 | "react-addons-test-utils": "0.14.x",
58 |
59 | "webpack-dev-server": "1.14.x",
60 | "babel-istanbul-loader": "0.1.x",
61 | "mocha": "2.4.x",
62 | "chai": "3.5.x",
63 | "chai-spies": "0.7.x",
64 | "chai-bem": "1.4.x",
65 | "karma-mocha": "0.2.x",
66 | "karma-mocha-reporter": "2.0.x",
67 | "karma-jsdom-launcher": "3.0.x",
68 | "karma-webpack": "1.7.x",
69 | "karma-coverage": "0.5.x",
70 | "karma-clear-screen-reporter": "1.0.x",
71 |
72 | "husky": "0.11.x"
73 | },
74 | "scripts": {
75 | "start": "start-runner ./tasks.js",
76 | "prepush": "npm start prepush"
77 | },
78 | "engines": {
79 | "node": ">=0.12",
80 | "npm": ">=2.7"
81 | },
82 | "license": "MIT"
83 | }
84 |
--------------------------------------------------------------------------------
/conf/webpack.common.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import webpack from 'webpack';
3 | import HtmlWebpackPlugin from 'html-webpack-plugin';
4 | import autoprefixer from 'autoprefixer';
5 |
6 | export default {
7 | cache: true,
8 | stats: {
9 | colors: true,
10 | reasons: false
11 | },
12 | output: {
13 | pathinfo: true
14 | },
15 | resolve: {
16 | alias: {
17 | '~': path.resolve('src/')
18 | }
19 | },
20 | module: {
21 | preLoaders: [
22 | {
23 | test: /\.js$/,
24 | loader: 'rebem-layers',
25 | query: {
26 | layers: [
27 | require('rebem-core-components'),
28 | require('rebem-theme-reset'),
29 | require('../src/theme-bootstrap'),
30 | {
31 | path: path.resolve('src/components/'),
32 | files: {
33 | main: 'index.js',
34 | styles: 'styles.less'
35 | },
36 | importFactory: true
37 | }
38 | ],
39 | consumers: [
40 | path.resolve('src/index')
41 | ]
42 | }
43 | },
44 | {
45 | test: /\.js$/,
46 | exclude: [
47 | path.resolve('node_modules/')
48 | ],
49 | loader: 'babel',
50 | query: {
51 | cacheDirectory: true
52 | }
53 | }
54 | ],
55 | loaders: [
56 | {
57 | test: /\.json$/,
58 | loader: 'json'
59 | }
60 | ]
61 | },
62 | postcss() {
63 | return [
64 | autoprefixer({
65 | browsers: [
66 | 'last 2 Chrome versions',
67 | 'last 2 Firefox versions',
68 | 'last 2 Safari versions',
69 | 'last 2 Explorer versions'
70 | ]
71 | })
72 | ];
73 | },
74 | plugins: [
75 | new webpack.DefinePlugin({
76 | 'process.env': {
77 | NODE_ENV: JSON.stringify(process.env.NODE_ENV)
78 | }
79 | }),
80 | new HtmlWebpackPlugin({
81 | template: 'src/assets/index.html'
82 | })
83 | ]
84 | };
85 |
--------------------------------------------------------------------------------
/conf/webpack.test.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | import webpackCommonConfig from './webpack.common';
4 |
5 | const testingSources = [
6 | path.resolve('src/components/')
7 | ];
8 |
9 | export default {
10 | ...webpackCommonConfig,
11 | resolve: {
12 | ...webpackCommonConfig.resolve,
13 | alias: {
14 | ...webpackCommonConfig.resolve.alias,
15 | test: path.resolve('test')
16 | }
17 | },
18 | module: {
19 | preLoaders: [
20 | {
21 | test: /\.js$/,
22 | loader: 'rebem-layers',
23 | query: {
24 | layers: [
25 | require('rebem-core-components'),
26 | require('rebem-theme-reset'),
27 | require('../src/theme-bootstrap'),
28 | {
29 | path: path.resolve('src/components/'),
30 | files: {
31 | main: 'index.js',
32 | styles: 'styles.less'
33 | },
34 | importFactory: true
35 | }
36 | ],
37 | consumers: [
38 | path.resolve('src/index.js'),
39 | path.resolve('test/')
40 | ]
41 | }
42 | },
43 | {
44 | test: /\.js$/,
45 | include: testingSources,
46 | loader: 'babel-istanbul',
47 | query: {
48 | cacheDirectory: true
49 | }
50 | },
51 | {
52 | test: /\.js$/,
53 | exclude: [
54 | ...testingSources,
55 | path.resolve('node_modules/')
56 | ],
57 | loader: 'babel',
58 | query: {
59 | cacheDirectory: true
60 | }
61 | }
62 | ],
63 | loaders: [
64 | ...webpackCommonConfig.module.loaders,
65 | {
66 | test: /\.css$/,
67 | loaders: [
68 | 'style',
69 | 'css?-minimize',
70 | 'postcss'
71 | ]
72 | },
73 | {
74 | test: /\.less$/,
75 | loaders: [
76 | 'style',
77 | 'css?-minimize',
78 | 'postcss',
79 | 'less'
80 | ]
81 | }
82 | ]
83 | }
84 | };
85 |
--------------------------------------------------------------------------------