1
0
mirror of https://github.com/yldio/copilot.git synced 2024-12-01 07:30:07 +02:00

Merge pull request #95 from yldio/rm-css

Remove css
This commit is contained in:
Tom Gallacher 2016-12-13 10:29:16 +00:00 committed by GitHub
commit e490935153
117 changed files with 6815 additions and 4921 deletions

2
.gitignore vendored
View File

@ -151,3 +151,5 @@ $RECYCLE.BIN/
/cloudapi-graphql/credentials.json
tap-xunit
/ui/dist

View File

@ -1,7 +1,14 @@
{
"sourceMaps": "both",
"presets": [
"react"
"react",
["env", {
"targets": {
"browsers": [
"last 2 versions"
]
}
}]
],
"plugins": [
"react-hot-loader/babel",

View File

@ -77,7 +77,7 @@
"jsx-a11y/aria-proptypes": 2,
"jsx-a11y/aria-role": 2,
"jsx-a11y/aria-unsupported-elements": 2,
"jsx-a11y/click-events-have-key-events": 2,
"jsx-a11y/click-events-have-key-events": 1,
"jsx-a11y/mouse-events-have-key-events": 2,
"jsx-a11y/heading-has-content": 2,
"jsx-a11y/html-has-lang": 2,
@ -88,7 +88,7 @@
"jsx-a11y/no-access-key": 2,
"jsx-a11y/no-marquee": 2,
"jsx-a11y/no-onchange": 2,
"jsx-a11y/no-static-element-interactions": 2,
"jsx-a11y/no-static-element-interactions": 1,
"jsx-a11y/onclick-has-focus": 2,
"jsx-a11y/onclick-has-role": 2,
"jsx-a11y/role-has-required-aria-props": 2,
@ -100,9 +100,7 @@
"object-curly-newline": [2, {
"minProperties": 1
}],
"sort-vars": [2, {
"ignoreCase": true
}],
"sort-vars": 2,
"prefer-const": 2,
"no-mixed-spaces-and-tabs": 2,
"new-cap": 2,

View File

@ -22,7 +22,7 @@ ui:
.PHONY: test
test: ui
BABEL_DISABLE_CACHE=1 NODE_ENV=test CONFIG=$(shell pwd)/webpack/index.js $(NYC) $(AVA) test/*.js $(TEST_ARGS)
NODE_ENV=test BABEL_DISABLE_CACHE=1 CONFIG=$(shell pwd)/webpack/index.js $(NYC) $(AVA) test/*.js $(TEST_ARGS)
XUNIT_DIR := ${CIRCLE_TEST_REPORTS}/tap-xunit
XUNIT := $(bindir)/tap-xunit

View File

@ -1,5 +1,5 @@
{
"name": "joyent-dashboard-frontend",
"name": "joyent-portal-frontend",
"version": "1.0.0",
"private": true,
"license": "private",
@ -31,36 +31,37 @@
"react-dom": "^15.4.1",
"react-hot-loader": "^3.0.0-beta.6",
"react-intl": "^2.1.5",
"react-intl-redux": "^0.1.1",
"react-intl-redux": "^0.2.0",
"react-redux": "^4.4.6",
"react-router": "^4.0.0-alpha.4",
"reduce-reducers": "^0.1.2",
"redux": "^3.6.0",
"redux-actions": "^1.1.0",
"redux-batched-actions": "^0.1.4",
"redux-batched-actions": "^0.1.5",
"redux-logger": "^2.7.4",
"redux-promise-middleware": "^4.2.0",
"redux-thunk": "^2.1.0",
"st": "^1.2.0"
"st": "^1.2.0",
"styled-components": "^1.1.3"
},
"devDependencies": {
"ava": "^0.17.0",
"babel-cli": "^6.18.0",
"babel-core": "^6.18.2",
"babel-core": "^6.20.0",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.2.8",
"babel-loader": "^6.2.9",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-syntax-async-functions": "^6.13.0",
"babel-plugin-transform-async-to-generator": "^6.16.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.19.0",
"babel-plugin-transform-object-rest-spread": "^6.20.2",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-plugin-webpack-loaders": "^0.8.0",
"babel-preset-env": "^1.0.2",
"babel-preset-react": "^6.16.0",
"babel-register": "^6.18.0",
"css-loader": "^0.26.1",
"enzyme": "^2.6.0",
"eslint": "^3.11.1",
"eslint": "^3.12.0",
"eslint-config-semistandard": "^7.0.0",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-babel": "^4.0.0",
@ -68,23 +69,17 @@
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-react": "^6.8.0",
"eslint-plugin-standard": "^2.0.1",
"extract-text-webpack-plugin": "^2.0.0-beta.4",
"fast-async": "^6.1.2",
"ignore-loader": "^0.1.2",
"json-loader": "^0.5.4",
"ncp": "^2.0.0",
"nyc": "^10.0.0",
"postcss-cssnext": "^2.9.0",
"postcss-loader": "^1.2.0",
"postcss-modules-values": "^1.2.2",
"pre-commit": "^1.1.3",
"pre-commit": "^1.2.1",
"react-addons-test-utils": "^15.4.1",
"style-loader": "^0.13.1",
"tap-xunit": "^1.4.0",
"thenify": "^3.2.1",
"webpack": "^2.1.0-beta.25",
"webpack-dev-server": "^1.16.2",
"webpack-shell-plugin": "^0.4.6"
"webpack-shell-plugin": "^0.4.9"
},
"ava": {
"failFast": true,

View File

@ -5,8 +5,6 @@ const ReactRouter = require('react-router');
const actions = require('@state/actions');
const Home = require('@containers/home');
const NotFound = require('@containers/not-found');
const Header = require('@components/header');
const {
updateRouter

View File

@ -1,3 +0,0 @@
.home {
background: red;
}

View File

@ -1,18 +1,26 @@
const React = require('react');
const ReactIntl = require('react-intl');
const styles = require('./home.css');
const Styled = require('styled-components');
const {
FormattedMessage
} = ReactIntl;
const {
default: styled
} = Styled;
const StyledWrapper = styled.div`
background-color: red;
`;
const Home = () => {
return (
<div className={styles.home}>
<StyledWrapper>
<h1>
<FormattedMessage id='greetings' />
</h1>
</div>
</StyledWrapper>
);
};

View File

@ -2,7 +2,6 @@
<html lang='en-US'>
<head>
<title>Joyent Frontend</title>
<link href='/static/bundle.css' rel='stylesheet' type='text/css'>
</head>
<body>
<div id='root'></div>
@ -10,6 +9,6 @@
<script src='/static/locales/pt-pt.js'></script>
<script src='/static/locales/en.js'></script>
<script src='/static/locales/en-us.js'></script>
<script src='/static/bundle.js'></script>
<script src='/static/main.js'></script>
</body>
</html>

View File

@ -6,24 +6,20 @@ const {
shallow
} = enzyme;
test('noop', (t) => {
t.deepEqual(1, 1);
test('renders <App> without exploding', (t) => {
const App = require('../src/containers/app');
const wrapper = shallow(<App />);
t.deepEqual(wrapper.length, 1);
});
// 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);
// });
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);
});

View File

@ -1,4 +1,3 @@
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const fs = require('fs');
@ -26,12 +25,10 @@ module.exports = {
output: {
path: STATIC,
publicPath: '/static/',
filename: 'bundle.js'
filename: '[name].js'
},
plugins: [
plugins['no-errors'],
plugins['extract-text'],
plugins['loader-options'],
plugins['define'],
plugins['shell']
],
@ -46,19 +43,6 @@ module.exports = {
exclude: /node_modules/,
include: [CONTEXT],
loaders: ['json-loader']
}, {
test: /\.css?$/,
exclude: /node_modules/,
include: [CONTEXT],
loader: ExtractTextPlugin.extract({
fallbackLoader: 'style-loader',
loader: [
'css-loader?',
'modules&importLoaders=1&',
'localIdentName=[name]__[local]___[hash:base64:5]!',
'postcss-loader'
].join('')
})
}]
}
};

View File

@ -1,4 +1,3 @@
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const pkg = require('../package.json');
const webpack = require('webpack');
const WebpackShellPlugin = require('webpack-shell-plugin');
@ -9,20 +8,6 @@ module.exports = {
'aggressive-merging': new webpack.optimize.AggressiveMergingPlugin(),
'hot-module-replacement': new webpack.HotModuleReplacementPlugin(),
'named-modules': new webpack.NamedModulesPlugin(),
'extract-text': new ExtractTextPlugin({
filename: 'bundle.css',
allChunks: true
}),
'loader-options': new webpack.LoaderOptionsPlugin({
options: {
postcss: {
plugins: [
require('postcss-modules-values'),
require('postcss-cssnext')()
]
}
}
}),
'define': new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),

View File

@ -1,4 +1,4 @@
const plugins = require('./plugins');
// const plugins = require('./plugins');
const base = require('./base');
@ -8,17 +8,16 @@ module.exports = Object.assign(base, {
'./index.js'
],
plugins: base.plugins.concat([
plugins['named-modules']
// plugins['occurrence-order'],
// plugins['aggressive-merging'],
// plugins['uglify-js']
])
});
/*
/**
* 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
*/
**/

View File

@ -24,14 +24,21 @@ module.exports = {
libraryTarget: 'commonjs2'
},
plugins: [
plugins['named-modules'],
plugins['no-errors'],
plugins['loader-options'],
plugins['define']
],
module: {
loaders: [{
test: /\.css?$/,
loader: 'ignore-loader'
test: /js?$/,
exclude: /node_modules/,
include: [CONTEXT],
loaders: ['babel-loader']
}, {
test: /\.json?$/,
exclude: /node_modules/,
include: [CONTEXT],
loaders: ['json-loader']
}]
}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,22 @@
{
"name": "joyent-dashboard",
"name": "joyent-portal",
"version": "1.0.0",
"description": "## Project Management",
"private": true,
"license": "MPL2",
"main": "index.js",
"homepage": "https://github.com/yldio/joyent-portal#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/yldio/joyent-portal.git"
},
"bugs": {
"url": "https://github.com/yldio/joyent-portal/issues"
},
"scripts": {
"test": "make test",
"precommit": "make -j4 lint",
"prepush": "make test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/yldio/joyent-dashboard.git"
},
"author": "",
"license": "MPL2",
"bugs": {
"url": "https://github.com/yldio/joyent-dashboard/issues"
},
"homepage": "https://github.com/yldio/joyent-dashboard#readme",
"dependencies": {
"husky": "^0.11.9"
},

View File

@ -5,7 +5,6 @@
"es2015"
],
"plugins": [
"react-hot-loader/babel",
"add-module-exports",
"transform-exponentiation-operator",
"syntax-async-functions",

View File

@ -1,6 +1,9 @@
src/components/base/*.css
node_modules
webpack/embed-markdown-loader/node_modules
coverage
.nyc_output
static/
!static/index.html
docs/static
!docs/static/index.html
docs/node_modules
docs/webpack/embed-markdown-loader
dist

View File

@ -1,6 +1,7 @@
/node_modules
node_modules
coverage
.nyc_output
docs/static
static
webpack/embed-markdown-loader
docs/node_modules
docs/webpack/embed-markdown-loader
dist

View File

@ -100,9 +100,7 @@
"object-curly-newline": [2, {
"minProperties": 1
}],
"sort-vars": [2, {
"ignoreCase": true
}],
"sort-vars": 2,
"prefer-const": 2,
"no-mixed-spaces-and-tabs": 2,
"new-cap": 2,
@ -118,7 +116,11 @@
"quotes": [2, "single"],
"max-depth": [2, 3],
"max-statements": [2, 60],
"max-len": [2, 80],
"max-len": [2, {
"ignoreComments": true,
"code": 80,
"tabWidth": 2
}],
"no-eq-null": 2,
"block-scoped-var": 2
}

7
ui/.storybook/config.js Normal file
View File

@ -0,0 +1,7 @@
const { configure } = require('@kadira/storybook');
function loadStories() {
require('../stories');
}
configure(loadStories, module);

View File

@ -1,8 +1,8 @@
/src/components/base/*.css
/node_modules
src/components/base/*.css
node_modules
coverage
.nyc_output
docs/static
static
webpack/embed-markdown-loader
docs/node_modules
docs/webpack/embed-markdown-loader
dist

View File

@ -1,5 +1,9 @@
{
"syntax": "scss",
"extends": "stylelint-config-standard",
"processors": [
"stylelint-processor-styled-components"
],
"rules": {
"color-hex-case": "upper",
"color-hex-length": "long",
@ -39,8 +43,6 @@
]
}],
"max-nesting-depth": 3,
"no-descending-specificity": true,
"no-duplicate-selectors": true,
"no-unknown-animations": true,
"custom-property-empty-line-before": null,
"selector-pseudo-class-no-unknown": [true, {

View File

@ -8,7 +8,7 @@ SERVE := $(bindir)/http-server
.PHONY: test
test:
BABEL_DISABLE_CACHE=1 NODE_ENV=test CONFIG=$(shell pwd)/webpack/index.js $(NYC) $(AVA) test/*.js $(TEST_ARGS)
BABEL_DISABLE_CACHE=1 NODE_ENV=test $(NYC) $(AVA) test/*.js $(TEST_ARGS)
XUNIT_DIR := ${CIRCLE_TEST_REPORTS}/tap-xunit
XUNIT := $(bindir)/tap-xunit
@ -16,11 +16,15 @@ XUNIT_OUTPUT := >> ${CIRCLE_TEST_REPORTS}/tap-xunit/xunit-$(NAME)
.PHONY: test-ci
test-ci:
mkdir -p $(XUNIT_DIR)
BABEL_DISABLE_CACHE=1 NODE_ENV=test CONFIG=$(shell pwd)/webpack/index.js $(NYC) $(AVA) test/*.js -t | $(XUNIT) $(XUNIT_OUTPUT).xml
BABEL_DISABLE_CACHE=1 NODE_ENV=test $(NYC) $(AVA) test/*.js -t | $(XUNIT) $(XUNIT_OUTPUT).xml
.PHONY: install-embed-markdown-loader
install-embed-markdown-loader:
cd webpack/embed-markdown-loader && yarn install --prefer-offline
cd docs/webpack/embed-markdown-loader && yarn install --prefer-offline
.PHONY: install-docs
install-docs:
cd docs && yarn install --prefer-offline
.PHONY: install
install: install-embed-markdown-loader
@ -36,7 +40,7 @@ install-production: compile clean
.PHONY: compile
compile: install
$(bindir)/webpack --config webpack/index.js
$(bindir)/babel src --out-dir dist --source-maps inline
.PHONY: build
build:
@ -54,7 +58,7 @@ clean:
.PHONY: lint
lint:
$(bindir)/eslint .
./scripts/stylelint
# -$(bindir)/stylelint './src/components/**/*.js'
.PHONY: lint-ci
lint-ci:

9
ui/docs/.babelrc Normal file
View File

@ -0,0 +1,9 @@
{
"extends": "../.babelrc",
"presets": [
"es2015"
],
"plugins": [
"react-hot-loader/babel"
]
}

View File

@ -1,54 +0,0 @@
/* - TOOD: Use our own grid
*/
const React = require('react');
const ReactRouter = require('react-router');
const Navigation = require('./navigation.js');
const Home = require('../home');
const Item = require('../item/');
// const Item = require('../../../src/components/range-slider');
const {
Base,
Container,
Row,
Column
} = require('../../../src');
const {
Match
} = ReactRouter;
module.exports = () => {
return (
<Base>
<Container fluid>
<Row>
<Column
md={2}
sm={3}
xs={12}
>
<Navigation />
</Column>
<Column
md={10}
sm={9}
xs={12}
>
<Match
component={Home}
exactly
pattern='/'
/>
<Match
component={Item}
pattern='/:parent?/:name'
/>
</Column>
</Row>
</Container>
</Base>
);
};

30
ui/docs/package.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "joyent-portal-ui-docs",
"description": "Joyent UI Framework Documentation",
"version": "1.0.0",
"license": "private",
"private": true,
"scripts": {
"start": "webpack-dev-server --config webpack/index.js",
"build": "NODE_ENV=production webpack --config webpack/index.js",
"clean-static": "git check-ignore static/** | xargs rm"
},
"dependencies": {
"dangerously-set-inner-html": "2.0.0",
"react": "^15.4.1",
"react-a11y": "^0.3.3",
"react-dom": "^15.4.1",
"react-hot-loader": "^3.0.0-beta.6",
"react-router": "^4.0.0-alpha.4",
"styled-components": "^1.1.3",
"title-case": "^2.1.0"
},
"devDependencies": {
"babel-loader": "^6.2.9",
"babel-preset-es2015": "^6.18.0",
"json-loader": "^0.5.4",
"raw-loader": "^0.5.1",
"webpack": "^2.1.0-beta.27",
"webpack-dev-server": "^1.16.2"
}
}

View File

@ -0,0 +1,14 @@
/* - TOOD: Use our own grid
*/
const React = require('react');
const {
Base,
} = require('@ui');
module.exports = () => {
return (
<Base />
);
};

View File

@ -2,7 +2,7 @@ const paramCase = require('param-case');
const React = require('react');
const ReactRouter = require('react-router');
const Docs = require('../../../src/docs');
const Docs = require('@root/mds');
const {
Link

View File

@ -3,7 +3,7 @@ const InnerHTML = require('dangerously-set-inner-html');
const React = require('react');
const titleCase = require('title-case');
const Docs = require('../../../src/docs');
const Docs = require('@root/mds');
const Item = ({
params

31
ui/docs/src/mds.js Normal file
View File

@ -0,0 +1,31 @@
module.exports = {
'Getting Started': require('@ui/getting-started.md'),
Guidelines: {
Overview: require('@ui/guidelines/overview.md'),
Layout: require('@ui/guidelines/layout.md')
},
// Components: {
// Avatar: require('@ui/components/avatar/readme.md'),
// Base: require('@ui/components/base/readme.md'),
// Container: require('@ui/components/container/readme.md'),
// Row: require('@ui/components/row/readme.md'),
// Input: require('@ui/components/input/readme.md'),
// Icon: require('@ui/components/icon/readme.md'),
// Radio: require('@ui/components/radio/readme.md'),
// 'Radio Group': require('@ui/components/radio-group/readme.md'),
// Select: require('@ui/components/select/readme.md'),
// Column: require('@ui/components/column/readme.md'),
// Button: require('@ui/components/button/readme.md'),
// 'Button Icon': require('@ui/components/button-icon/readme.md'),
// 'Range Slider': require('@ui/components/range-slider/readme.md'),
// Toggle: require('@ui/components/toggle/readme.md'),
// Notificaton: require('@ui/components/notification/readme.md'),
// Checkbox: require('@ui/components/checkbox/readme.md'),
// Tab: require('@ui/components/tabs/tab/readme.md'),
// Tabs: require('@ui/components/tabs/readme.md'),
// Widget: require('@ui/components/widget/readme.md'),
// Pagination: require('@ui/components/pagination/readme.md'),
// Modal: require('@ui/components/modal/readme.md')
// },
FAQ: require('@ui/faq.md')
};

11
ui/docs/static/index.html vendored Normal file
View File

@ -0,0 +1,11 @@
<!doctype html>
<html lang='en-US'>
<head>
<title>Joyent UI Framework</title>
<link href="theme.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id='root'></div>
<script src='main.js'></script>
</body>
</html>

68
ui/docs/webpack/base.js Normal file
View File

@ -0,0 +1,68 @@
const path = require('path');
const plugins = require('./plugins');
const CONTEXT = path.join(__dirname, '../../');
const STATIC = path.join(__dirname, '../static');
const DOCS = path.join(CONTEXT, 'docs');
const NODE_MODULES = path.join(DOCS, 'node_modules');
const SRC = path.join(CONTEXT, 'src');
const MODULES = [
path.join(DOCS, 'node_modules'),
path.join(CONTEXT, 'node_modules')
];
const INCLUDE = [
DOCS,
SRC
];
module.exports = {
context: CONTEXT,
entry: './docs/src/index.js',
resolveLoader: {
alias: {
'embed-markdown-loader': path.join(__dirname, './embed-markdown-loader'),
'babel-loader': path.join(NODE_MODULES, 'babel-loader'),
'json-loader': path.join(NODE_MODULES, 'json-loader'),
'raw-loader': path.join(NODE_MODULES, 'raw-loader')
}
},
resolve: {
modules: MODULES,
alias: {
'@root': path.join(DOCS, 'src'),
'@ui': SRC
}
},
output: {
path: STATIC,
publicPath: '/',
filename: '[name].js'
},
plugins: [
plugins['named-modules'],
plugins['no-errors'],
plugins['loader-options'],
plugins['define']
],
module: {
rules: [{
test: /js?$/,
exclude: [/node_modules/g],
include: INCLUDE,
loader: 'babel-loader'
}, {
test: /\.json?$/,
exclude: [/node_modules/g],
include: INCLUDE,
loader: 'json-loader'
}, {
test: /\.md?$/,
exclude: [/node_modules/g],
include: INCLUDE,
loader: 'raw-loader!embed-markdown-loader'
}]
}
};

View File

@ -0,0 +1,30 @@
const base = require('./base');
const plugins = require('./plugins');
const path = require('path');
const STATIC = path.join(__dirname, '../static');
const devServer = {
contentBase: [
STATIC
],
hot: true,
compress: true,
lazy: false,
historyApiFallback: {
index: './index.html'
}
};
module.exports = Object.assign(base, {
entry: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/only-dev-server',
'./docs/src/index.js'
],
plugins: base.plugins.concat([
plugins['hot-module-replacement']
]),
devServer
});

View File

@ -1,10 +1,5 @@
const WebpackShellPlugin = require('webpack-shell-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
const cssFunctions = require('../src/shared/functions');
const mixins = path.join(__dirname, '../src/shared/mixins.css');
const pkg = require('../package.json');
module.exports = {
@ -13,27 +8,8 @@ module.exports = {
'hot-module-replacement': new webpack.HotModuleReplacementPlugin(),
'named-modules': new webpack.NamedModulesPlugin(),
'no-errors': new webpack.NoErrorsPlugin(),
'extract-text': new ExtractTextPlugin({
filename: '[name].css',
allChunks: true
}),
'loader-options': new webpack.LoaderOptionsPlugin({
options: {
postcss: {
plugins: [
require('postcss-import')(),
require('postcss-constants')({}),
require('postcss-at-rules-variables')(),
require('postcss-functions')({
functions: cssFunctions
}),
require('postcss-mixins')({
mixinsFiles: mixins
}),
require('postcss-for'),
require('postcss-cssnext')()
]
},
'embed-markdown-loader': {
mode: 'plain'
}
@ -53,10 +29,5 @@ module.exports = {
comments: false,
indent_level: 2
}
}),
'shell': new WebpackShellPlugin({
onBuildEnd: [
'npm run build-docs-static'
]
})
};
};

View File

@ -0,0 +1,18 @@
const plugins = require('./plugins');
const base = require('./base');
module.exports = Object.assign(base, {
plugins: base.plugins.concat([
plugins['occurrence-order'],
plugins['aggressive-merging'],
plugins['uglify-js']
])
});
/*
* 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
*/

3027
ui/docs/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,50 +1,47 @@
{
"name": "joyent-dashboard-ui",
"name": "joyent-portal-ui",
"version": "1.0.0",
"license": "MPL2",
"private": true,
"license": "private",
"main": "static/ui",
"main": "dist/index.js",
"scripts": {
"start": "webpack-dev-server --config webpack/index.js",
"start": "cd docs && npm start",
"lint": "make lint",
"test": "make test",
"build": "NODE_ENV=production webpack --config webpack/index.js",
"clean-static": "git check-ignore static/** | xargs rm",
"build-docs-static": "sh scripts/build-docs-static.sh"
"build": "make compile",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"dependencies": {
"classnames": "^2.2.5",
"color": "^1.0.1",
"invariant": "^2.2.2",
"color": "^1.0.2",
"lodash.find": "^4.6.0",
"lodash.first": "^3.0.0",
"lodash.flatten": "^4.4.0",
"lodash.get": "^4.4.2",
"lodash.isfunction": "^3.0.8",
"lodash.isstring": "^4.0.1",
"lodash.isundefined": "^3.0.1",
"param-case": "^2.1.0",
"random-natural": "^1.0.3",
"react": "^15.4.1",
"react-a11y": "^0.3.3",
"react-icons": "^2.2.1",
"react-dom": "^15.4.1",
"reduce-css-calc": "^1.3.0",
"traverse": "^0.6.6"
"styled-components": "^1.1.3"
},
"devDependencies": {
"@kadira/storybook": "^2.34.0",
"ava": "^0.17.0",
"babel-core": "^6.18.2",
"babel-cli": "^6.18.0",
"babel-core": "^6.20.0",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.2.8",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-syntax-async-functions": "^6.13.0",
"babel-plugin-transform-object-rest-spread": "^6.19.0",
"babel-preset-es2015": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.20.2",
"babel-preset-react": "^6.16.0",
"babel-register": "^6.18.0",
"css-loader": "^0.26.1",
"css-modules-require-hook": "^4.0.5",
"dangerously-set-inner-html": "2.0.0",
"enzyme": "^2.6.0",
"eslint": "^3.11.1",
"eslint": "^3.12.0",
"eslint-config-semistandard": "^7.0.0",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-babel": "^4.0.0",
@ -52,44 +49,20 @@
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-react": "^6.8.0",
"eslint-plugin-standard": "^2.0.1",
"extract-text-webpack-plugin": "^2.0.0-beta.4",
"graceful-fs": "^4.1.11",
"json-loader": "^0.5.4",
"lodash.get": "^4.4.2",
"memory-fs": "^0.3.0",
"memory-fs": "^0.4.1",
"nyc": "^10.0.0",
"param-case": "^2.1.0",
"postcss-at-rules-variables": "0.0.26",
"postcss-constants": "^0.2.0",
"postcss-cssnext": "^2.9.0",
"postcss-for": "^2.1.1",
"postcss-functions": "^2.1.1",
"postcss-import": "9.0.0",
"postcss-loader": "^1.2.0",
"postcss-mixins": "^5.4.0",
"postcss-modules-values": "^1.2.2",
"pre-commit": "^1.1.3",
"raw-loader": "^0.5.1",
"pre-commit": "^1.2.0",
"react-addons-test-utils": "^15.4.1",
"react-dom": "^15.4.1",
"react-hot-loader": "^3.0.0-beta.6",
"react-router": "^4.0.0-alpha.4",
"st": "^1.2.0",
"style-loader": "^0.13.1",
"stylelint": "^7.6.0",
"stylelint-config-standard": "^15.0.0",
"stylelint-webpack-plugin": "^0.4.0",
"tap-xunit": "^1.4.0",
"title-case": "^2.1.0",
"webpack": "^2.1.0-beta.25",
"webpack-dev-server": "^1.16.2",
"webpack-shell-plugin": "^0.4.6"
"stylelint-processor-styled-components": "^0.0.4",
"tap-xunit": "^1.4.0"
},
"ava": {
"failFast": true,
"cache": false,
"require": [
"css-modules-require-hook/preset",
"babel-register"
],
"babel": "inherit"

View File

@ -1,3 +0,0 @@
echo $(pwd)
# cp -r ../static/* ../docs/static/
# mv ../docs/static/index.html ../docs/

View File

@ -1,32 +0,0 @@
#!/usr/bin/env node
const StyleLintPlugin = require('stylelint-webpack-plugin');
const webpack = require('webpack');
const MemoryFS = require('memory-fs');
const config = require('../webpack/base');
const mfs = new MemoryFS();
const compiler = webpack(Object.assign(config, {
plugins: config.plugins.concat([
new StyleLintPlugin({
configFile: '.stylelintrc',
files: [
'**/*.css'
],
failOnError: true
})
])
}));
mfs.mkdirpSync(config.output.path);
compiler.outputFileSystem = mfs;
compiler.run((err, stats) => {
if (err) {
throw err;
}
});
process.on('unhandledRejection', () => {
process.exit(1);
});

View File

@ -1,10 +1,44 @@
// TODO: use a checkbox
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const composers = require('../../shared/composers');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const Avatar = ({
const {
verticallyAlignCenter
} = composers;
const {
remcalc
} = fns;
const {
default: styled
} = Styled;
const Picture = styled.img`
${verticallyAlignCenter}
max-width: 100%;
`;
const Letter = styled.p`
font-size: 2rem;
margin-top: 0;
margin-bottom: 1em;
line-height: 1.5;
`;
const Avatar = styled.div`
border-radius: 50%;
height: ${remcalc(50)};
overflow: hidden;
position: relative;
text-align: center;
width: ${remcalc(50)};
`;
module.exports = ({
alt,
className,
color,
@ -16,46 +50,35 @@ const Avatar = ({
srcset,
style
}) => {
const cn = classNames(
className,
styles.avatar
);
style = {
const _style = {
...style,
background: color
};
const letter = name.split('')[0];
const letter = name[0];
const av = src ? (
<img
<Picture
alt={alt || name}
className={styles.picture}
crossOrigin={crossorigin}
longdesc={longdesc}
sizes={sizes}
src={src}
srcSet={srcset}
style={style}
/>
) : (
<p
className={styles.letter}
style={style}
>
<Letter>
{letter}
</p>
</Letter>
);
return (
<div className={cn} style={style}>
<Avatar className={className} style={_style}>
{av}
</div>
</Avatar>
);
};
Avatar.propTypes = {
module.exports.propTypes = {
alt: React.PropTypes.string,
className: React.PropTypes.string,
color: React.PropTypes.string,
@ -67,7 +90,3 @@ Avatar.propTypes = {
srcset: React.PropTypes.string,
style: React.PropTypes.object
};
module.exports = Avatar;

View File

@ -1,17 +0,0 @@
.avatar {
border-radius: 50%;
height: remcalc(50);
overflow: hidden;
position: relative;
text-align: center;
width: remcalc(50);
}
.letter {
font-size: 2rem;
}
.picture {
composes: verticle_align_center from "../../shared/composers.css";
max-width: 60%;
}

View File

@ -0,0 +1,12 @@
const Styled = require('styled-components');
const {
css
} = Styled;
module.exports = css`
html, body {
font-size: 16px;
margin: 0;
}
`;

View File

@ -1,28 +1,478 @@
const React = require('react');
const classNames = require('classnames');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const Styled = require('styled-components');
const Base = ({
children,
className,
style
}) => {
const cn = classNames(
className,
styles.base
);
const {
forms,
links,
tables,
typography
} = constants;
return (
<div className={cn} style={style}>
{children}
</div>
);
};
const {
default: styled
} = Styled;
Base.propTypes = {
children: React.PropTypes.node,
className: React.PropTypes.string,
style: React.PropTypes.object
};
module.exports = styled.div`
font-family: -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 1rem;
line-height: 1.5;
color: #373A3C;
background-color: #FFFFFF;
module.exports = Base;
/**************************************************************************
* NORMALIZE.CSS *
**************************************************************************/
& article,
& aside,
& details,
& figcaption,
& figure,
& footer,
& header,
& main,
& menu,
& nav,
& section,
& summary {
display: block;
}
& audio,
& canvas,
& progress,
& video {
display: inline-block;
}
& audio:not([controls]) {
display: none;
height: 0;
}
& progress {
vertical-align: baseline;
}
& template,
& [hidden] {
display: none;
}
& a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
& a:active,
& a:hover {
outline-width: 0;
}
& abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
& b,
& strong {
font-weight: inherit;
}
& b,
& strong {
font-weight: bolder;
}
& dfn {
font-style: italic;
}
& h1 {
font-size: 2em;
margin: 0.67em 0;
}
& mark {
background-color: #ff0;
color: #000;
}
& small {
font-size: 80%;
}
& sub,
& sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
& sub {
bottom: -0.25em;
}
& sup {
top: -0.5em;
}
& img {
border-style: none;
}
& svg:not(:root) {
overflow: hidden;
}
& code,
& kbd,
& pre,
& samp {
font-family: monospace, monospace;
font-size: 1em;
}
& figure {
margin: 1em 40px;
}
& hr {
-webkit-box-sizing: content-box;
box-sizing: content-box;
height: 0;
overflow: visible;
}
& button,
& input,
& optgroup,
& select,
& textarea {
font: inherit;
margin: 0;
}
& optgroup {
font-weight: bold;
}
& button,
& input {
overflow: visible;
}
& button,
& select {
text-transform: none;
}
& button,
& [type="button"],
& [type="reset"],
& [type="submit"] {
-webkit-appearance: button;
}
& button::-moz-focus-inner,
& [type="button"]::-moz-focus-inner,
& [type="reset"]::-moz-focus-inner,
& [type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
& button:-moz-focusring,
& [type="button"]:-moz-focusring,
& [type="reset"]:-moz-focusring,
& [type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
& fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
& legend {
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
& textarea {
overflow: auto;
}
& [type="checkbox"],
& [type="radio"] {
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
& [type="number"]::-webkit-inner-spin-button,
& [type="number"]::-webkit-outer-spin-button {
height: auto;
}
& [type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
& [type="search"]::-webkit-search-cancel-button,
& [type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
& ::-webkit-input-placeholder {
color: inherit;
opacity: 0.54;
}
& ::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
/**************************************************************************
* BOOTSTRAP REBOOT *
**************************************************************************/
& *,
& *::before,
& *::after {
box-sizing: inherit;
}
& @-ms-viewport {
width: device-width;
}
& [tabindex="-1"]:focus {
outline: none !important;
}
/**
* Typography
*/
& h1,
& h2,
& h3,
& h4,
& h5,
& h6 {
margin-top: 0;
margin-bottom: .5rem;
}
& p {
margin-top: 0;
margin-bottom: 1rem;
}
& abbr[title],
& abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted ${typography.abbrBorderColor};
}
& address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
& ol,
& ul,
& dl {
margin-top: 0;
margin-bottom: 1rem;
}
& ol ol,
& ul ul,
& ol ul,
& ul ol {
margin-bottom: 0;
}
& dt {
font-weight: ${typography.dtFontWeight};
}
& dd {
margin-bottom: .5rem;
margin-left: 0; /* Undo browser default */
}
& blockquote {
margin: 0 0 1rem;
}
/**
* Links
*/
& a {
color: ${links.color};
text-decoration: ${links.decoration};
&:focus,
&:hover {
color: ${links.hoverColor};
text-decoration: ${links.hoverDecoration};
}
&:focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
}
& a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
&:focus,
&:hover {
color: ${links.hoverColor};
text-decoration: ${links.hoverDecoration};
}
&:focus {
outline: none;
}
}
/**
* Code
*/
& pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
}
/**
* Figures
*/
& figure {
margin: 0 0 1rem;
}
/**
* Images
*/
& img {
vertical-align: middle;
}
& [role="button"] {
cursor: pointer;
}
& a,
& area,
& button,
& [role="button"],
& input,
& label,
& select,
& summary,
& textarea {
touch-action: manipulation;
}
/**
* Tables
*/
& table {
border-collapse: collapse;
background-color: ${tables.bg};
}
& caption {
padding-top: ${tables.cellPadding};
padding-bottom: ${tables.cellPadding};
color: ${typography.textMuted};
text-align: left;
caption-side: bottom;
}
& th {
text-align: left;
}
/**
* Forms
*/
& label {
display: inline-block;
margin-bottom: .5rem;
}
& button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
& input,
& button,
& select,
& textarea {
line-height: inherit;
}
& input[type="radio"],
& input[type="checkbox"] {
&:disabled {
cursor: ${forms.cursorDisabled};
}
}
& input[type="date"],
& input[type="time"],
& input[type="datetime-local"],
& input[type="month"] {
-webkit-appearance: listbox;
}
& textarea {
resize: vertical;
}
& fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
& legend {
display: block;
width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
}
& input[type="search"] {
-webkit-appearance: none;
}
`;

View File

@ -1,610 +0,0 @@
/* from:
*
* reboot.css v4.0.0-alpha.5
* MIT License
* github.com/twbs/bootstrap
*
* normalize.css v4.2.0
* MIT License
* github.com/necolas/normalize.css
*/
~forms: "../../shared/constants.js";
~links: "../../shared/constants.js";
~tables: "../../shared/constants.js";
~typography: "../../shared/constants.js";
:root {
--cursor-disabled: ~forms.cursorDisabled;
--link-color: ~links.linkColor;
--link-decoration: ~links.linkDecoration;
--link-hover-color: ~links.linkHoverColor;
--link-hover-decoration: ~links.linkHoverDecoration;
--table-bg: ~tables.tableBg;
--table-cell-padding: ~tables.tableCellPadding;
--dt-font-weight: ~typography.dtFontWeight;
--text-muted: ~typography.textMuted;
--abbr-border-color: ~typography.abbrBorderColor;
}
.base {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 1rem;
line-height: 1.5;
color: #373A3C;
background-color: #FFFFFF;
& :global {
/**************************************************************************
* NORMALIZE.CSS *
**************************************************************************/
& article,
& aside,
& details,
& figcaption,
& figure,
& footer,
& header,
& main,
& menu,
& nav,
& section,
& summary {
display: block;
}
& audio,
& canvas,
& progress,
& video {
display: inline-block;
}
& audio:not([controls]) {
display: none;
height: 0;
}
& progress {
vertical-align: baseline;
}
& template,
& [hidden] {
display: none;
}
& a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
& a:active,
& a:hover {
outline-width: 0;
}
& abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
& b,
& strong {
font-weight: inherit;
}
& b,
& strong {
font-weight: bolder;
}
& dfn {
font-style: italic;
}
& h1 {
font-size: 2em;
margin: 0.67em 0;
}
& mark {
background-color: #ff0;
color: #000;
}
& small {
font-size: 80%;
}
& sub,
& sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
& sub {
bottom: -0.25em;
}
& sup {
top: -0.5em;
}
& img {
border-style: none;
}
& svg:not(:root) {
overflow: hidden;
}
& code,
& kbd,
& pre,
& samp {
font-family: monospace, monospace;
font-size: 1em;
}
& figure {
margin: 1em 40px;
}
& hr {
-webkit-box-sizing: content-box;
box-sizing: content-box;
height: 0;
overflow: visible;
}
& button,
& input,
& optgroup,
& select,
& textarea {
font: inherit;
margin: 0;
}
& optgroup {
font-weight: bold;
}
& button,
& input {
overflow: visible;
}
& button,
& select {
text-transform: none;
}
& button,
& [type="button"],
& [type="reset"],
& [type="submit"] {
-webkit-appearance: button;
}
& button::-moz-focus-inner,
& [type="button"]::-moz-focus-inner,
& [type="reset"]::-moz-focus-inner,
& [type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
& button:-moz-focusring,
& [type="button"]:-moz-focusring,
& [type="reset"]:-moz-focusring,
& [type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
& fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
& legend {
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
& textarea {
overflow: auto;
}
& [type="checkbox"],
& [type="radio"] {
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
& [type="number"]::-webkit-inner-spin-button,
& [type="number"]::-webkit-outer-spin-button {
height: auto;
}
& [type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
& [type="search"]::-webkit-search-cancel-button,
& [type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
& ::-webkit-input-placeholder {
color: inherit;
opacity: 0.54;
}
& ::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
/**************************************************************************
* BOOTSTRAP REBOOT *
**************************************************************************/
& *,
& *::before,
& *::after {
box-sizing: inherit;
}
& @-ms-viewport {
width: device-width;
}
/*
* Suppress the focus outline on elements that cannot be accessed via keyboard.
* This prevents an unwanted focus outline from appearing around elements that
* might still respond to pointer events.
*
* Credit: https://github.com/suitcss/base
*/
& [tabindex="-1"]:focus {
outline: none !important;
}
/**
* Typography
*/
/* Remove top margins from headings
*
* By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top
* margin for easier control within type scales as it avoids margin collapsing.
*/
& h1,
& h2,
& h3,
& h4,
& h5,
& h6 {
margin-top: 0;
margin-bottom: .5rem;
}
/* Reset margins on paragraphs
*
* Similarly, the top margin on `<p>`s get reset. However, we also reset the
* bottom margin to use `rem` units instead of `em`.
*/
& p {
margin-top: 0;
margin-bottom: 1rem;
}
/* Abbreviations and acronyms */
& abbr[title],
/* Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257 */
& abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted var(--abbr-border-color);
}
& address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
& ol,
& ul,
& dl {
margin-top: 0;
margin-bottom: 1rem;
}
& ol ol,
& ul ul,
& ol ul,
& ul ol {
margin-bottom: 0;
}
& dt {
font-weight: var(--dt-font-weight);
}
& dd {
margin-bottom: .5rem;
margin-left: 0; /* Undo browser default */
}
& blockquote {
margin: 0 0 1rem;
}
/**
* Links
*/
& a {
color: var(--link-color);
text-decoration: var(--link-decoration);
&:focus,
&:hover {
color: var(--link-hover-color);
text-decoration: var(--link-hover-decoration);
}
&:focus {
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
}
/* And undo these styles for placeholder links/named anchors (without href)
* which have not been made explicitly keyboard-focusable (without tabindex).
* It would be more straightforward to just use a[href] in previous block, but that
* causes specificity issues in many other styles that are too complex to fix.
* See https://github.com/twbs/bootstrap/issues/19402
*/
& a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
&:focus,
&:hover {
color: var(--link-hover-color);
text-decoration: var(--link-hover-decoration);
}
&:focus {
outline: none;
}
}
/**
* Code
*/
& pre {
/* Remove browser default top margin */
margin-top: 0;
/* Reset browser default of `1em` to use `rem`s */
margin-bottom: 1rem;
/* Normalize v4 removed this property, causing `<pre>` content to break out of wrapping code snippets */
overflow: auto;
}
/**
* Figures
*/
& figure {
/* Normalize adds `margin` to `figure`s as browsers apply it inconsistently.
* We reset that to create a better flow in-page.
*/
margin: 0 0 1rem;
}
/**
* Images
*/
& img {
/* By default, `<img>`s are `inline-block`. This assumes that, and vertically
* centers them. This won't apply should you reset them to `block` level.
*/
vertical-align: middle;
/* Note: `<img>`s are deliberately not made responsive by default.
* For the rationale behind this, see the comments on the `.img-fluid` class.
*/
}
/* iOS "clickable elements" fix for role="button"
*
* Fixes "clickability" issue (and more generally, the firing of events such as focus as well)
* for traditionally non-focusable elements with role="button"
* see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
*/
& [role="button"] {
cursor: pointer;
}
/* Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.
*
* In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11
* DON'T remove the click delay when `<meta name="viewport" content="width=device-width">` is present.
* However, they DO support removing the click delay via `touch-action: manipulation`.
* See:
* * https://v4-alpha.getbootstrap.com/content/reboot/#click-delay-optimization-for-touch
* * http://caniuse.com/#feat=css-touch-action
* * https://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay
*/
& a,
& area,
& button,
& [role="button"],
& input,
& label,
& select,
& summary,
& textarea {
touch-action: manipulation;
}
/**
* Tables
*/
& table {
/* No longer part of Normalize since v4 */
border-collapse: collapse;
/* Reset for nesting within parents with `background-color`. */
background-color: var(--table-bg);
}
& caption {
padding-top: var(--table-cell-padding);
padding-bottom: var(--table-cell-padding);
color: var(--text-muted);
text-align: left;
caption-side: bottom;
}
& th {
/* Centered by default, but left-align-ed to match the `td`s below. */
text-align: left;
}
/**
* Forms
*/
& label {
/* Allow labels to use `margin` for spacing. */
display: inline-block;
margin-bottom: .5rem;
}
/* Work around a Firefox/IE bug where the transparent `button` background
* results in a loss of the default `button` focus styles.
*
* Credit: https://github.com/suitcss/base/
*/
& button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
& input,
& button,
& select,
& textarea {
/* Normalize includes `font: inherit;`, so `font-family`. `font-size`, etc are */
/* properly inherited. However, `line-height` isn't inherited there. */
line-height: inherit;
}
& input[type="radio"],
& input[type="checkbox"] {
/* Apply a disabled cursor for radios and checkboxes.
*
* Note: Neither radios nor checkboxes can be readonly.
*/
&:disabled {
cursor: var(--cursor-disabled);
}
}
& input[type="date"],
& input[type="time"],
& input[type="datetime-local"],
& input[type="month"] {
/* Remove the default appearance of temporal inputs to avoid a Mobile Safari
* bug where setting a custom line-height prevents text from being vertically
* centered within the input.
*
* Bug report: https://github.com/twbs/bootstrap/issues/11266
*/
-webkit-appearance: listbox;
}
& textarea {
/* Textareas should really only resize vertically so they don't break their (horizontal) containers. */
resize: vertical;
}
& fieldset {
/* Chrome and Firefox set a `min-width: min-content;` on fieldsets,
* so we reset that to ensure it behaves more like a standard block element.
* See https://github.com/twbs/bootstrap/issues/12359.
*/
min-width: 0;
/* Reset the default outline behavior of fieldsets so they don't affect page layout. */
padding: 0;
margin: 0;
border: 0;
}
& legend {
/* Reset the entire legend element to match the `fieldset` */
display: block;
width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
}
& input[type="search"] {
/* This overrides the extra rounded corners on search inputs in iOS so that our
* `.form-control` class can properly style them. Note that this cannot simply
* be added to `.form-control` as it's not specific enough. For details, see
* https://github.com/twbs/bootstrap/issues/11586.
*/
-webkit-appearance: none;
}
/* todo: needed? */
& output {
display: inline-block;
}
/* Always hide an element with the `hidden` HTML attribute (from PureCSS). */
& [hidden] {
display: none !important;
}
/**************************************************************************
* GOBAL HELPERS *
**************************************************************************/
& .clearfix {
&::before,
&::after {
content: "";
display: table;
}
&::after {
clear: both;
}
}
}
}

View File

@ -1,36 +0,0 @@
const React = require('react');
const classNames = require('classnames');
const styles = require('./style.css');
const Button = require('../button');
const ButtonIcon = ({
name = 'beer',
className,
iconSet = 'fa',
style
}) => {
const Component = require(`react-icons/lib/${iconSet}/${name}`);
const cn = classNames(
className,
styles.icon
);
return (
<div>
<Button>
<Component className={cn} style={style} />
</Button>
</div>
);
};
ButtonIcon.propTypes = {
className: React.PropTypes.string,
iconSet: React.PropTypes.string.isRequired,
name: React.PropTypes.string.isRequired,
style: React.PropTypes.object
};
module.exports = ButtonIcon;

View File

@ -1,37 +0,0 @@
# `<ButtonIcon>`
## demo
```embed
const React = require('react');
const ReactDOM = require('react-dom/server');
const Base = require('../base');
const Container = require('../container');
const Row = require('../row');
const Column = require('../column');
const ButtonIcon = require('./index.js');
const styles = require('./style.css');
nmodule.exports = ReactDOM.renderToString(
<Base>
<Row>
<Column>
<ButtonIcon iconSet='fa' name='beer' />
</Column>
</Row>
</Base>
);
```
## usage
```js
const React = require('react');
const ButtonIcon = require('ui/button-icon');
module.exports = () => {
return (
<ButtonIcon iconSet='fa' name='beer' />
);
}
```

View File

@ -1,3 +0,0 @@
.icon {
font-size: inherit;
}

View File

@ -1,68 +1,52 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const match = require('../../shared/match');
const Styled = require('styled-components');
const Button = ({
autoFocus,
children,
className,
disabled = false,
form,
formAction,
formEncType,
formMethod,
formNoValidate,
formTarget,
name,
secondary = false,
style,
type,
value
}) => {
const cn = classNames(
className,
styles.button,
secondary ? styles.secondary : styles.primary,
disabled ? styles.inactive : '',
);
const {
colors,
boxes
} = constants;
return (
<button
autoFocus={autoFocus}
className={cn}
disabled={disabled}
form={form}
formAction={formAction}
formEncType={formEncType}
formMethod={formMethod}
formNoValidate={formNoValidate}
formTarget={formTarget}
name={name}
style={style}
type={type}
value={value}
>
{children}
</button>
);
const {
remcalc
} = fns;
const {
default: styled,
} = Styled;
// TODO: this should come from constants
// and be calculated accordingly
const styles = {
primaryBorder: '#2532BB',
secondaryColor: '#646464',
...colors
};
Button.propTypes = {
autoFocus: React.PropTypes.bool,
children: React.PropTypes.node,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
form: React.PropTypes.string,
formAction: React.PropTypes.string,
formEncType: React.PropTypes.string,
formMethod: React.PropTypes.string,
formNoValidate: React.PropTypes.bool,
formTarget: React.PropTypes.string,
name: React.PropTypes.string,
secondary: React.PropTypes.bool,
style: React.PropTypes.object,
type: React.PropTypes.string,
value: React.PropTypes.string
};
const background = match({
secondary: styles.background,
disabled: styles.inactiveBackground,
}, styles.brandPrimary);
module.exports = Button;
const border = match({
secondary: styles.border,
disabled: styles.inactiveBorder
}, styles.primaryBorder);
const color = match({
secondary: styles.secondaryColor,
disabled: styles.inactiveColor
}, styles.background);
module.exports = styled.button`
border-radius: ${remcalc(boxes.borderRadius)};
box-shadow: ${boxes.bottomShaddow};
font-size: ${remcalc(16)};
min-width: ${remcalc(120)};
padding: ${remcalc('18 24')};
background: ${background};
border: solid 1px ${border};
color: ${color};
`;

View File

@ -1,43 +0,0 @@
~colors: "../../shared/constants.js";
~boxes: "../../shared/constants.js";
:root {
--primary-background: ~colors.brandPrimary;
--primary-border: #2532BB;
--primary-color: #FFFFFF;
--secondary-backgroud: #FFFFFF;
--secondary-border: #D8D8D8;
--secondary-color: #646464;
--inactive-background: #F9F9F9;
--inactive-border: #D8D8D8;
--inactive-color: #737373;
}
@define-mixin button $background, $border-color, $color {
background: $background;
border: 1px solid $border-color;
color: $color;
}
.button {
border-radius: remcalc(~boxes.borderRadius);
box-shadow: ~boxes.bottomShaddow;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: remcalc(16);
min-width: remcalc(120);
padding: remcalc(18 24);
&.primary {
@add-mixin button var(--primary-background), var(--primary-border), var(--primary-color);
}
&.secondary {
@add-mixin button var(--secondary-backgroud), var(--secondary-border), var(--secondary-color);
}
&.inactive {
@add-mixin button var(--inactive-background), var(--inactive-border), var(--inactive-color);
}
}

View File

@ -1,6 +1,66 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const Styled = require('styled-components');
const {
boxes
} = constants;
const {
default: styled,
} = Styled;
const StyledInput = styled.input`
visibility: hidden;
&:checked + label::after {
opacity: 1;
}
&:disabled + label {
background-color: rgb(249, 249, 249);
}
&:disabled + label::after {
opacity: 0.3;
}
`;
const StyledLabel = styled.label`
color: rgb(100, 100, 100);
position: absolute;
width: 24px;
height: 24px;
top: 0;
border-radius: ${boxes.borderRadius};
background-color: rgb(255, 255, 255);
box-shadow: ${boxes.insetShaddow};
border: ${boxes.border.unchecked};
&::after {
opacity: 0;
content: '';
position: absolute;
width: 9px;
height: 4px;
background: transparent;
top: 7px;
left: 7px;
border: 3px solid #333;
border-top: none;
border-right: none;
transform: rotate(-45deg);
}
&:hover {
&::after {
opacity: 0.3;
}
}
`;
const StyledDiv = styled.div`
width: 24px;
height: 24px;
position: relative;
`;
const Checkbox = ({
checked = false,
@ -17,32 +77,24 @@ const Checkbox = ({
style,
tabIndex
}) => {
const cn = classNames(
className,
styles.checkbox,
checked ? styles.checked : '',
disabled ? styles.disabled : ''
);
return (
<label className={styles.label} htmlFor={id}>
<input
<StyledDiv>
<StyledInput
checked={checked}
className={cn}
disabled={disabled}
form={form}
id={id}
name={name}
onChange={onChange}
readOnly={readOnly}
required={required}
selectionDirection={selectionDirection}
style={style}
tabIndex={tabIndex}
type='checkbox'
/>
<span>{children}</span>
</label>
<StyledLabel>
<span>{children}</span>
</StyledLabel>
</StyledDiv>
);
};

View File

@ -1,3 +0,0 @@
.label {
color: #646464;
}

View File

@ -3,62 +3,82 @@
* github.com/roylee0704/react-flexbox-grid/blob/master/src/components/Col.js
*/
const flatten = require('lodash.flatten');
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const isUndefined = require('lodash.isundefined');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const breakpoints = [
'xs',
'sm',
'md',
'lg'
];
const {
breakpoints,
sizes
} = constants;
const getClasses = (props) => {
return flatten(breakpoints.map((size) => {
const number = props[size];
const offset = props[`${size}Offset`];
const {
calc
} = fns;
return [
number ? styles[`${size}-${number}`] : '',
offset ? styles[`${size}-offset-${offset}`] : ''
];
})).filter(Boolean);
const {
default: styled,
} = Styled;
const padding = sizes.halfGutterWidth || '0.5rem';
const width = (fallback) => (size) => (props) => {
return !isUndefined(props[size])
? calc(`(${props[size]} / ${sizes.gridColumns}) * 100%`)
: fallback;
};
const Column = (props) => {
const {
children,
className,
reverse,
style
} = props;
const flexBasis = width('auto');
const maxWidth = width('none');
const marginLeft = width(0);
const cn = classNames(
className,
styles.column,
reverse ? styles.reverse : '',
...getClasses(props)
);
return (
<div className={cn} style={style}>
{children}
</div>
);
const breakpoint = (prop, size) => {
return (...args) => (props) => props[prop] && breakpoints[size](...args);
};
Column.propTypes = {
children: React.PropTypes.node,
className: React.PropTypes.string,
reverse: React.PropTypes.bool,
style: React.PropTypes.object,
...breakpoints.reduce((all, bp) => ({
...all,
[`${bp}Offset`]: React.PropTypes.number,
[bp]: React.PropTypes.number
}), {})
};
const sm = breakpoint('sm', 'small');
const smOffset = breakpoint('smOffset', 'small');
const md = breakpoint('md', 'medium');
const mdOffset = breakpoint('mdOffset', 'medium');
const lg = breakpoint('lg', 'large');
const lgOffset = breakpoint('lgOffset', 'large');
module.exports = Column;
module.exports = styled.div`
box-sizing: border-box;
flex: 0 0 auto;
padding-left: ${padding};
padding-right: ${padding};
flex-grow: 1;
flex-basis: ${flexBasis('xs')};
max-width: ${maxWidth('xs')};
margin-left: ${marginLeft('xsOffset')};
${sm`
flex-basis: ${flexBasis('sm')};
max-width: ${maxWidth('sm')};
`}
${smOffset`
margin-left: ${marginLeft('smOffset')};
`}
${md`
flex-basis: ${flexBasis('md')};
max-width: ${maxWidth('md')};
`}
${mdOffset`
margin-left: ${marginLeft('mdOffset')};
`}
${lg`
flex-basis: ${flexBasis('lg')};
max-width: ${maxWidth('lg')};
`}
${lgOffset`
margin-left: ${marginLeft('lgOffset')};
`}
`;

View File

@ -1,62 +0,0 @@
/*
* based on
* https://github.com/kristoferjoseph/flexboxgrid/blob/master/dist/flexboxgrid.css
*/
~sizes: "../../shared/constants.js";
~breakpoints: "../../shared/constants.js";
:root {
--half-gutter-width: ~sizes.halfGutterWidth;
--grid-columns: 12; /* Cannot import values and use them within the loop */
}
@custom-media --sm-viewport ~breakpoints.sm;
@custom-media --md-viewport ~breakpoints.md;
@custom-media --lg-viewport ~breakpoints.lg;
@define-mixin viewport $size {
&.$(size) {
flex-basis: 0;
flex-grow: 1;
max-width: 100%;
}
@for $i from 1 to var(--grid-columns) {
&.$(size)-$i {
flex-basis: calc(($i / var(--grid-columns)) * 100%);
max-width: calc(($i / var(--grid-columns)) * 100%);
}
}
@for $i from 0 to var(--grid-columns) {
&.$(size)-offset-$i {
margin-left: calc(($i / var(--grid-columns)) * 100%);
}
}
}
.column {
box-sizing: border-box;
flex: 0 0 auto;
padding-left: var(--half-gutter-width, 0.5rem);
padding-right: var(--half-gutter-width, 0.5rem);
&.reverse {
flex-direction: column-reverse;
}
@mixin viewport xs;
@media ( --sm-viewport ) {
@mixin viewport sm;
}
@media ( --md-viewport ) {
@mixin viewport md;
}
@media ( --lg-viewport ) {
@mixin viewport lg;
}
}

View File

@ -3,33 +3,39 @@
* github.com/roylee0704/react-flexbox-grid/blob/master/src/components/Grid.js
*/
const React = require('react');
const classNames = require('classnames');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const Styled = require('styled-components');
const Container = ({
fluid = false,
className,
children,
style
}) => {
const cn = classNames(
className,
styles[fluid ? 'container-fluid' : 'container']
);
const {
breakpoints,
sizes
} = constants;
return (
<div className={cn} style={style}>
{children}
</div>
);
};
const {
default: styled,
css
} = Styled;
Container.propTypes = {
children: React.PropTypes.node,
className: React.PropTypes.string,
fluid: React.PropTypes.bool,
style: React.PropTypes.object
};
const fluid = (props) => props.fluid && css`
padding-left: ${sizes.outerMargin};
padding-right: ${sizes.outerMargin};
`;
module.exports = Container;
module.exports = styled.div`
margin-left: auto;
margin-right: auto;
${fluid}
${breakpoints.small`
width: ${sizes.containerSm || '46rem'};
`}
${breakpoints.medium`
width: ${sizes.containerMd || '61rem'};
`}
${breakpoints.large`
width: ${sizes.containerLg || '71rem'};
`}
`;

View File

@ -1,3 +1 @@
# `<Container>`
## usage

View File

@ -1,41 +0,0 @@
/*
* based on
* https://github.com/kristoferjoseph/flexboxgrid/blob/master/dist/flexboxgrid.css
*/
~sizes: "../../shared/constants.js";
~breakpoints: "../../shared/constants.js";
:root {
--outer-margin: ~sizes.outerMargin;
--container-sm: ~sizes.containerSm;
}
@custom-media --sm-viewport ~breakpoints.sm;
@custom-media --md-viewport ~breakpoints.md;
@custom-media --lg-viewport ~breakpoints.lg;
.container-fluid,
.container {
margin-left: auto;
margin-right: auto;
}
.container-fluid {
padding-left: var(--outer-margin);
padding-right: var(--outer-margin);
}
.container {
@media ( --sm-viewport ) {
width: var(--container-sm, 46rem);
}
@media ( --md-viewport ) {
width: var(--container-md, 61rem);
}
@media ( --lg-viewport ) {
width: var(--container-lg, 71rem);
}
}

View File

@ -1,6 +1,14 @@
const React = require('react');
const classNames = require('classnames');
const styles = require('./style.css');
const Styled = require('styled-components');
const {
default: styled,
css
} = Styled;
const styles = css`
font-size: inherit;
`;
const Icon = ({
name = 'beer',
@ -8,17 +16,11 @@ const Icon = ({
iconSet = 'fa',
style
}) => {
const Component = require(`react-icons/lib/${iconSet}/${name}`);
const cn = classNames(
className,
styles.icon
);
const Icon = require(`react-icons/lib/${iconSet}/${name}`);
const Component = styled(Icon)(styles);
return (
<div className={cn}>
<Component style={style} />
</div>
<Component className={className} style={style} />
);
};

View File

@ -1,6 +1,43 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const composers = require('../../shared/composers');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const {
remcalc
} = fns;
const {
baseBox
} = composers;
const {
default: styled
} = Styled;
const Label = styled.label`
color: #464646;
`;
const InputField = styled.input`
background: ${constants.colors.background};
display: block;
font-size: 16px;
height: ${remcalc(50)};
padding-left: ${remcalc(15)};
padding-right: ${remcalc(15)};
visibility: visible;
width: 100%;
${baseBox()}
&:focus {
border-color: ${constants.colors.borderSelected};
outline: none;
}
`;
const Input = ({
autoComplete,
@ -12,6 +49,7 @@ const Input = ({
id,
inputMode,
label,
labelledby,
list,
name,
onChange,
@ -29,23 +67,15 @@ const Input = ({
const _label = label || children;
const _children = label && children ? children : null;
const cn = classNames(
className,
styles['input-group']
);
const labelledby = `${styles.label}-label`;
return (
<div className={cn}>
<label className={styles.label} htmlFor={id}>
<div>
<Label htmlFor={id}>
{_label}
</label>
<input
</Label>
<InputField
aria-labelledby={labelledby}
autoComplete={autoComplete}
autoFocus={autoFocus}
className={styles.input}
disabled={disabled}
form={form}
id={id}
@ -78,6 +108,7 @@ Input.propTypes = {
id: React.PropTypes.string,
inputMode: React.PropTypes.string,
label: React.PropTypes.string,
labelledby: React.PropTypes.string,
list: React.PropTypes.string,
name: React.PropTypes.string,
onChange: React.PropTypes.func,

View File

@ -1,33 +0,0 @@
@import "../../shared/mixins.css";
~boxes: "../../shared/constants.js";
~colors: "../../shared/constants.js";
:root {
--background-color: ~colors.background;
--border-color: ~colors.border;
--border-selected-color: ~colors.borderSelected;
--border-radius: remcalc(~boxes.borderRadius);
--inset-box-shadow: ~boxes.insetShaddow;
}
.input {
background: var(--background-color);
display: block;
height: 50px;
padding-left: 15px;
padding-right: 15px;
visibility: visible;
width: 100%;
@add-mixin create-base-box-properties;
&:focus {
border-color: var(--border-selected-color);
outline: none;
}
}
.label {
color: #464646;
}

View File

@ -1,98 +1,86 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const Styled = require('styled-components');
const Modal = React.createClass({
const {
default: styled
} = Styled;
propTypes: {
children: React.PropTypes.node,
className: React.PropTypes.string,
name: React.PropTypes.string,
trigger: React.PropTypes.func.isRequired
},
const StyledModal = styled.div`
background: white;
display: block;
left: 50%;
margin: 0 auto;
padding: 20px;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
z-index: 1;
`;
getInitialState: function() {
return {
active: false
};
},
const StyledClose = styled.button`
background-color: #FFFFFF;
border: solid 1px #D8D8D8;
border-radius: 4px;
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.05);
color: black;
cursor: #000000;
font-size: 20px;
padding: 0 10px;
position: absolute;
right: -20px;
text-align: center;
text-decoration: none;
top: -15px;
`;
handleReveal: function(e) {
e.preventDefault();
this.setState({
active: this.state.active ? false : true
});
},
const StyledOverlay = styled.div`
background: rgba(0, 0, 0, 0.4);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 0;
`;
render: function() {
const {
children,
className,
name,
trigger
} = this.props;
const {
active
} = this.state;
const {
handleReveal
} = this;
const triggerClass = classNames(
className,
styles.trigger
);
const modal = classNames(
className,
styles.modal,
);
const overlay = classNames(
className,
styles.overlay,
);
return (
<div>
<span
aria-label={name}
className={triggerClass}
href="#"
onClick={handleReveal}
role="link"
tabIndex={0}
>
{trigger()}
</span>
{ active ? (
<div
aria-label="overlay"
className={overlay}
onClick={handleReveal}
role="link"
tabIndex={-2}
/>
) : null }
{ active ? (
<div aria-label={name} className={modal} >
<button
className={styles.close}
href='#'
onClick={handleReveal}
role="dialog"
tabIndex={-1}
>X</button>
{children}
</div>
) : null }
</div>
);
const Modal = ({
active = true,
children,
className,
handleDismiss,
name,
style
}) => {
if (!active) {
return null;
}
});
return (
<div className={className} style={style}>
<StyledOverlay
aria-label='overlay'
role='link'
tabIndex={-2}
/>
<StyledModal aria-label={name}>
<StyledClose
onClick={handleDismiss}
role='dialog'
tabIndex={-1}
>X</StyledClose>
{children}
</StyledModal>
</div>
);
};
Modal.propTypes = {
active: React.PropTypes.bool,
children: React.PropTypes.node,
className: React.PropTypes.string,
handleDismiss: React.PropTypes.func,
name: React.PropTypes.string,
style: React.PropTypes.object
};
module.exports = Modal;

View File

@ -1,43 +0,0 @@
.overlay {
background: rgba(0, 0, 0, 0.4);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 0;
}
.modal {
background: white;
display: block;
left: 50%;
margin: 0 auto;
padding: 20px;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
z-index: 1;
}
.close {
background-color: #FFFFFF;
border: solid 1px #D8D8D8;
border-radius: 4px;
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.05);
color: black;
cursor: #000000;
font-size: 20px;
padding: 0 10px;
position: absolute;
right: -20px;
text-align: center;
text-decoration: none;
top: -15px;
}
.trigger {
cursor: pointer;
display: inline-block;
outline: none;
}

View File

@ -1,52 +1,72 @@
const classNames = require('classnames');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const match = require('../../shared/match');
const React = require('react');
const styles = require('./style.css');
const Icon = require('../icon');
const Styled = require('styled-components');
const {
colors
} = constants;
const {
remcalc
} = fns;
const {
prop: matchProp
} = match;
const {
default: styled
} = Styled;
const background = matchProp({
warning: colors.warningLight,
alert: colors.alertLight,
}, 'transparent');
const border = matchProp({
warning: colors.warning,
alert: 'red',
}, 'none');
const StyledNotification = styled.div`
border-radius: 4px;
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.05);
display: inline-block;
height: 100%;
background-color: ${background('type')};
border: ${border('type')};
`;
const StyledContent = styled.div`
float: left;
padding: ${remcalc(20)};
`;
const Notificaton = ({
children,
className,
style,
type = '',
icon = ''
type = ''
}) => {
const cn = classNames(
className,
styles[`notification__${type}`],
styles.notification
);
const iconClass = classNames(
className,
styles.notification__icon,
styles[`notification__icon--${type}`]
);
return (
<div
className={cn}
<StyledNotification
className={className}
style={style}
type={type}
>
{ icon ? (
<Icon
className={iconClass}
iconSet="fa"
name={icon}
/>
) : null }
<div className={styles.notification__content}>
<StyledContent>
{children}
</div>
</div>
</StyledContent>
</StyledNotification>
);
};
Notificaton.propTypes = {
children: React.PropTypes.object,
className: React.PropTypes.str,
icon: React.PropTypes.str,
style: React.PropTypes.object,
type: React.PropTypes.str
};

View File

@ -1,54 +0,0 @@
~colors: "../../shared/constants.js";
@define-mixin block-decoration $background, $color {
background-color: $background;
border: solid 1px $color;
}
@define-mixin icon-decoration $background, $color {
background: $background;
color: $color;
}
.notification {
border-radius: 4px;
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.05);
display: inline-block;
height: 100%;
&__warning {
@add-mixin block-decoration ~colors.warningLight, ~colors.warning;
}
&__alert {
@add-mixin block-decoration ~colors.alertLight, red;
}
&__content {
float: left;
padding: remcalc(20);
}
&__icon {
display: inline-block;
float: left;
height: 100%;
min-height: 100%;
padding: remcalc(15);
text-align: center;
& svg {
position: relative;
top: 50%;
transform: translateY(-100%);
}
&--warning {
@add-mixin icon-decoration ~colors.warning, white;
}
&--alert {
@add-mixin icon-decoration ~colors.alert, white;
}
}
}

View File

@ -1,36 +1,97 @@
const classNames = require('classnames');
const composers = require('../../shared/composers');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const React = require('react');
const styles = require('./style.css');
const Styled = require('styled-components');
const {
baseBox
} = composers;
const {
boxes
} = constants;
const {
rndId
} = fns;
const {
default: styled
} = Styled;
const classNames = {
active: rndId()
};
const StyledUl = styled.ul`
display: inline-block;
list-style: none;
margin: 0;
padding: 0;
`;
const StyledLi = styled.li`
align-items: center;
cursor: pointer;
display: flex;
float: left;
height: 50px;
justify-content: center;
margin-right: 10px;
min-width: 50px;
padding-left: 15px;
padding-right: 15px;
position: relative;
${baseBox()}
&:last-child {
margin-right: inherit;
}
&:not( .${classNames.active} ):hover {
border: ${boxes.border.checked};
}
& a:hover {
text-decoration: none;
}
&.${classNames.active} {
cursor: default;
}
`;
const Pagination = ({
children,
className,
label
label,
style
}) => {
const cn = classNames(
className,
styles.pagination
);
const pages = React.Children.map(children, (child) => {
const cn = classNames(
child.props.className,
child.props.active ? styles.active : '',
styles.pagination_item
);
const cn = `
${child.props.className}
${child.props.active ? classNames.active : ''}
`.trim();
return (
<li className={cn}>
<StyledLi className={cn}>
{child}
</li>
</StyledLi>
);
});
return (
<nav aria-label={label} className={cn}>
<ul className={styles.paginatation_list}>
<nav
aria-label={label}
className={className}
style={style}
>
<StyledUl>
{pages}
</ul>
</StyledUl>
</nav>
);
};
@ -38,7 +99,8 @@ const Pagination = ({
Pagination.propTypes = {
children: React.PropTypes.node,
className: React.PropTypes.string,
label: React.PropTypes.string
label: React.PropTypes.string,
style: React.PropTypes.object
};
module.exports = Pagination;

View File

@ -1,50 +0,0 @@
@import "../../shared/mixins.css";
~boxes: "../../shared/constants.js";
~colors: "../../shared/constants.js";
:root {
--border-checked: ~boxes.border.checked;
--border-unchecked: ~boxes.border.unchecked;
--border-radius: remcalc(~boxes.borderRadius);
--bottom-shaddow: ~boxes.bottomShaddow;
}
.paginatation_list {
display: inline-block;
list-style: none;
margin: 0;
padding: 0;
}
.pagination_item {
align-items: center;
cursor: pointer;
display: flex;
float: left;
height: 50px;
justify-content: center;
margin-right: 10px;
min-width: 50px;
padding-left: 15px;
padding-right: 15px;
position: relative;
@add-mixin create-base-box-properties;
&:last-child {
margin-right: inherit;
}
&:not( .active ):hover {
border: var(--border-checked);
}
& a:hover {
text-decoration: none;
}
&.active {
cursor: default;
}
}

View File

@ -1,6 +1,69 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const Styled = require('styled-components');
const {
boxes
} = constants;
const {
default: styled,
} = Styled;
const StyledInput = styled.input`
visibility: hidden;
&:checked + label::after {
opacity: 1;
}
&:disabled + label {
background-color: rgb(249, 249, 249);
}
&:disabled + label::after {
opacity: 0.3;
}
`;
const border = 1;
const StyledLabel = styled.label`
color: rgb(100, 100, 100);
position: absolute;
width: ${24 - border}px;
height: ${24 - border}px;
top: 0;
border-radius: 100%;
background-color: rgb(255, 255, 255);
box-shadow: ${boxes.insetShaddow};
border: ${boxes.border.unchecked};
&::after {
opacity: 0;
content: '';
position: absolute;
width: 8px;
height: 8px;
background: rgb(100, 100, 100);
top: ${(23 / 2) - 4}px;
left: ${(23 / 2) - 4}px;
border-radius: 100%;
transform: rotate(-45deg);
}
&:hover {
&::after {
opacity: 0.3;
}
}
`;
const StyledDiv = styled.div`
width: 24px;
height: 24px;
position: relative;
`;
const TextLabel = styled.label`
`;
const Radio = ({
checked,
@ -20,23 +83,13 @@ const Radio = ({
tabIndex,
value
}) => {
const _label = label || children;
const _children = label && children ? children : null;
const cn = classNames(
className,
styles.radio
);
const labelledby = `${styles.label}-label`;
return (
<div className={cn}>
<label className={styles.label} htmlFor={id}>
<input
aria-labelledby={labelledby}
<TextLabel>
<StyledDiv>
<StyledInput
checked={checked}
className={styles.input}
defaultChecked={defaultChecked}
disabled={disabled}
form={form}
@ -50,14 +103,12 @@ const Radio = ({
type='radio'
value={value}
/>
<span className={styles.span} id={labelledby}>
{_label}
</span>
</label>
<StyledLabel />
</StyledDiv>
<span>
{_children}
</span>
</div>
</TextLabel>
);
};

View File

@ -1,36 +0,0 @@
@import "../../shared/mixins.css";
:root {
--radio-radius: 20px;
--radio-border-size: calc(var(--radio-radius) / 4);
--dot-color: #646464;
--border-color: #CFD1D1;
}
.radio {
cursor: pointer;
& .label {
display: block;
}
& .span {
margin-left: remcalc(30);
margin-right: remcalc(20);
@add-mixin pseduo-element before, var(--radio-radius), var(--radio-radius), -1px, auto, auto, -30px {
border: var(--radio-border-size) solid white;
border-radius: 50%;
box-shadow: 0 0 0 1px var(--border-color);
}
}
& .input {
display: none;
visibility: hidden;
&:checked ~ .span::before {
background: var(--dot-color);
}
}
}

View File

@ -1,30 +1,145 @@
const classNames = require('classnames');
const composers = require('../../shared/composers');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const React = require('react');
const styles = require('./style.css');
const Styled = require('styled-components');
const {
baseBox
} = composers;
const {
colors
} = constants;
const {
remcalc
} = fns;
const {
default: styled,
css
} = Styled;
const rangeTrack = css`
background: ${colors.brandPrimary};
cursor: pointer;
height: ${remcalc(6)};
width: 100%;
${baseBox({
radius: remcalc(25)
})}
`;
const rangeThumb = css`
-webkit-appearance: none;
background: #FFFFFF;
cursor: pointer;
height: ${remcalc(24)};
position: relative;
top: -10px;
width: ${remcalc(36)};
${baseBox()}
`;
const rangeLower = css`
background: ${colors.brandPrimary};
height: 6px;
${baseBox({
radius: remcalc(50),
border: 'none'
})}
`;
const rangeUpper = css`
background: #E6E6E6;
height: 6px;
${baseBox({
radius: remcalc(50)
})}
`;
const StyledRange = styled.input`
-webkit-appearance: none;
border: none;
box-shadow: none;
display: block;
margin: ${remcalc('10 0')};
visibility: visible;
width: 100%;
&::-moz-focus-outer {
border: 0;
}
&::-moz-range-track {
${rangeTrack}
}
&::-ms-track {
${rangeTrack}
}
&::-webkit-slider-runnable-track {
${rangeTrack}
}
&::-moz-range-thumb {
${rangeThumb}
}
&::-ms-thumb {
${rangeThumb}
}
&::-webkit-slider-thumb {
${rangeThumb}
}
&::-moz-range-progress {
${rangeLower}
}
&::-ms-fill-lower {
${rangeLower}
}
&::-ms-fill-upper {
${rangeUpper}
}
&:focus {
outline: none;
}
&:focus::-webkit-slider-runnable-track {
background: ${colors.brandPrimary};
}
&:focus::-ms-fill-lower {
${rangeLower}
}
&:focus::-ms-fill-upper {
${rangeUpper}
}
`;
const RangeSlider = ({
className,
onChange,
style
}) => {
const slider = classNames(
className,
styles.range_input
);
// TODO: Get rid of inline styles
style = {
...style,
display: 'block'
};
return (
<input
className={slider}
<StyledRange
className={className}
onChange={onChange}
style={style}
type="range"
type='range'
/>
);
};

View File

@ -1,120 +0,0 @@
@import "../../shared/mixins.css";
~colors: "../../shared/constants.js";
~boxes: "../../shared/constants.js";
:root {
--primary-background: ~colors.brandPrimary;
--box-shaddow: ~boxes.bottomShaddow;
--box-border: ~boxes.border.unchecked;
--box-radius: ~boxes.borderRadius;
}
/*
MIXINS - Defining Mixins for slider
*/
@define-mixin range-track {
background: var(--primary-background);
cursor: pointer;
height: remcalc(6);
width: 100%;
@add-mixin create-base-box-properties remcalc(25);
}
@define-mixin range-thumb {
-webkit-appearance: none;
background: #FFFFFF;
cursor: pointer;
height: remcalc(24);
position: relative;
top: -10px;
width: remcalc(36);
@add-mixin create-base-box-properties;
}
@define-mixin range-lower {
background: var(--primary-background);
height: 6px;
@add-mixin create-base-box-properties remcalc(50), none;
}
@define-mixin range-upper {
background: #E6E6E6;
height: 6px;
@add-mixin create-base-box-properties remcalc(50);
}
/*
SELECTORS - Styleing variou psuedo selectos
TODO: Complied incorrectly when selectors are in a comma seperated list
*/
.range_input {
-webkit-appearance: none;
border: none;
box-shadow: none;
display: block; /* Try and figure out why display none is being set in doc.css */
margin: remcalc(10 0);
visibility: visible;
width: 100%;
&::-moz-focus-outer {
border: 0;
}
&::-moz-range-track {
@add-mixin range-track;
}
&::-ms-track {
@add-mixin range-track;
}
&::-webkit-slider-runnable-track {
@add-mixin range-track;
}
&::-moz-range-thumb {
@add-mixin range-thumb;
}
&::-ms-thumb {
@add-mixin range-thumb;
}
&::-webkit-slider-thumb {
@add-mixin range-thumb;
}
&::-moz-range-progress {
@add-mixin range-lower;
}
&::-ms-fill-lower {
@add-mixin range-lower;
}
&::-ms-fill-upper {
@add-mixin range-upper;
}
&:focus {
outline: none;
}
&:focus::-webkit-slider-runnable-track {
background: var(--primary-background);
}
&:focus::-ms-fill-lower {
@add-mixin range-lower;
}
&:focus::-ms-fill-upper {
@add-mixin range-upper;
}
}

View File

@ -3,92 +3,87 @@
* github.com/roylee0704/react-flexbox-grid/blob/master/src/components/Row.js
*/
const flatten = require('lodash.flatten');
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const match = require('../../shared/match');
const sizeMatch = require('./size-match');
const Styled = require('styled-components');
const breakpoints = [
'xs',
'sm',
'md',
'lg'
];
const {
breakpoints,
sizes
} = constants;
const modifiers = [
'start',
'center',
'end',
'top',
'middle',
'bottom',
'around',
'between',
'first',
'last'
];
const {
default: styled
} = Styled;
const getClasses = (props) => {
return flatten(modifiers.map((name) => {
const value = props[name];
const margin = sizes.gutterCompensation || '-0.5rem';
if (!value) {
return;
}
const direction = (size) => match(sizeMatch(size, {
reverse: 'row-reverse'
}), 'row');
const bps = (() => {
if (value === true) {
return breakpoints;
}
const justify = (size) => match(sizeMatch(size, {
center: 'center',
end: 'flex-end',
around: 'space-around',
between: 'space-between'
}), 'flex-start');
if (Array.isArray(value)) {
return value;
}
const textAlign = (size) => match(sizeMatch(size, {
center: 'center',
end: 'end'
}), 'start');
return [value];
})();
const alignItems = (size) => match(sizeMatch(size, {
top: 'flex-start',
middle: 'center',
bottom: 'flex-end'
}), 'stretch');
return flatten(bps.map(bp => styles[`${name}-${bp}`]));
})).filter(Boolean);
};
// const order = (size) => match(sizeMatch(size, {
// first: -1,
// last: 1
// }), 0);
const Row = (props) => {
const {
className,
reverse,
children,
style
} = props;
/**
* ```html
* <row center top={['xs', 'sm']} first='lg' />
* ```
**/
module.exports = styled.div`
box-sizing: border-box;
display: flex;
flex: 0 1 auto;
flex-wrap: wrap;
const cn = classNames(
className,
styles.row,
reverse ? styles.reverse : '',
...getClasses(props)
);
margin-left: ${margin};
margin-right: ${margin};
return (
<div className={cn} style={style}>
{children}
</div>
);
};
flex-direction: ${direction('xs')};
justify-content: ${justify('xs')};
text-align: ${textAlign('xs')};
align-items: ${alignItems('xs')};
const ModificatorType = React.PropTypes.oneOfType([
React.PropTypes.bool,
React.PropTypes.arrayOf(React.PropTypes.oneOf(breakpoints)),
React.PropTypes.oneOf(breakpoints)
]);
${breakpoints.small`
flex-direction: ${direction('sm')};
justify-content: ${justify('sm')};
text-align: ${textAlign('sm')};
align-items: ${alignItems('sm')};
Row.propTypes = {
children: React.PropTypes.node,
className: React.PropTypes.string,
reverse: React.PropTypes.bool,
style: React.PropTypes.object,
...modifiers.reduce((all, m) => ({
...all,
[m]: ModificatorType
}), {})
};
`}
module.exports = Row;
${breakpoints.medium`
flex-direction: ${direction('md')};
justify-content: ${justify('md')};
text-align: ${textAlign('md')};
align-items: ${alignItems('md')};
`}
${breakpoints.large`
flex-direction: ${direction('lg')};
justify-content: ${justify('lg')};
text-align: ${textAlign('lg')};
align-items: ${alignItems('lg')};
`}
`;

View File

@ -3,16 +3,18 @@
## demo
```embed
const styleSheet = require('styled-components/lib/models/StyleSheet')
const React = require('react');
const ReactDOM = require('react-dom/server');
const Row = require('./index.js');
const Container = require('../container');
const Button = require('../button');
// const styles = styleSheet.rules().map(rule => rule.cssText).join('\n')
nmodule.exports = ReactDOM.renderToString(
<Row center='xs' start='sm'>
<Button>1</Button>
<Button>2</Button>
<pre>{styleSheet}</pre>
<button>1</button>
<button>2</button>
</Row>
);
```

View File

@ -0,0 +1,26 @@
const isString = require('lodash.isstring');
/**
* given a size, a prop and a value, we want to get that value
* if the rule matches the size
*
* ```js
* sizeApply('xs', 'xs', 'row-reverse'); //=> 'row-reverse'
* sizeApply('xs', true, 'row-reverse'); //=> 'row-reverse'
* sizeApply('xs', ['xs', 'sm'], 'row-reverse'); //=> 'row-reverse'
* sizeApply('xs', 'sm', 'row-reverse'); //=> false
* sizeApply('xs', false, 'row-reverse'); //=> false
* sizeApply('xs', ['sm', 'lg'], 'row-reverse'); //=> false
* ```
**/
module.exports = (size, prop, value) => {
if (isString(prop) && prop === size) {
return value;
}
if (Array.isArray(prop) && (prop.indexOf(size) >= 0)) {
return value;
}
return prop ? value : false;
};

View File

@ -0,0 +1,25 @@
const sizeApply = require('./size-apply');
/**
* this is the middle man between sizeApply and match. we want to turn an object
* of {prop: value} into { prop: (props) => {} } so that each prop can only be
* applied based on size
*
* ```js
* sizeMatch('xs', {
* center: 'center',
* })
*
* // {
* // center: (props) => sizeApply('xs', props['xs'], 'center')
* // }
* ```
**/
module.exports = (size, rules) => {
return Object.keys(rules).reduce((acc, rule) => {
return {
...acc,
[rule]: (props) => sizeApply(size, props[rule], rules[rule])
};
}, rules);
};

View File

@ -1,88 +0,0 @@
/*
* based on
* https://github.com/kristoferjoseph/flexboxgrid/blob/master/dist/flexboxgrid.css
*/
~sizes: "../../shared/constants.js";
~breakpoints: "../../shared/constants.js";
:root {
--gutter-compensation: ~sizes.gutterCompensation;
}
@custom-media --sm-viewport ~breakpoints.sm;
@custom-media --md-viewport ~breakpoints.md;
@custom-media --lg-viewport ~breakpoints.lg;
@define-mixin viewport $size {
&.start-$(size) {
justify-content: flex-start;
text-align: start;
}
&.center-$(size) {
justify-content: center;
text-align: center;
}
&.end-$(size) {
justify-content: flex-end;
text-align: end;
}
&.top-$(size) {
align-items: flex-start;
}
&.middle-$(size) {
align-items: center;
}
&.bottom-$(size) {
align-items: flex-end;
}
&.around-$(size) {
justify-content: space-around;
}
&.between-$(size) {
justify-content: space-between;
}
&.first-$(size) {
order: -1;
}
&.last-$(size) {
order: 1;
}
}
.row {
box-sizing: border-box;
display: flex;
flex: 0 1 auto;
flex-direction: row;
flex-wrap: wrap;
margin-left: var(--gutter-compensation, -0.5rem);
margin-right: var(--gutter-compensation, -0.5rem);
&.reverse {
flex-direction: row-reverse;
}
@mixin viewport xs;
@media ( --sm-viewport ) {
@mixin viewport sm;
}
@media ( --md-viewport ) {
@mixin viewport md;
}
@media ( --lg-viewport ) {
@mixin viewport lg;
}
}

View File

@ -1,6 +1,37 @@
const classNames = require('classnames');
const fns = require('../../shared/functions');
const React = require('react');
const styles = require('./style.css');
const Styled = require('styled-components');
const {
rndId
} = fns;
const {
default: styled
} = Styled;
// TODO: this should be a constant
const StyledLabel = styled.div`
color: #464646;
`;
const StyledSelect = styled.select`
color: #464646;
/* select[multiple] is valid CSS syntax - not added to lint library yet */
/* stylelint-disable */
&[multiple] {
/* stylelint-enable */
padding-left: 0;
padding-right: 0;
& :global option {
padding-left: 15px;
padding-right: 15px;
width: 100%;
}
}
`;
const Select = ({
autoFocus,
@ -8,24 +39,20 @@ const Select = ({
className,
disabled,
form,
id,
id = rndId(),
label,
multiple,
name,
required,
selected
}) => {
const cn = classNames(
className,
styles['select-group']
);
return (
<div className={cn}>
<label className={styles.label} htmlFor={id}>{label}</label>
<select
<div className={className}>
<StyledLabel htmlFor={id}>
{label}
</StyledLabel>
<StyledSelect
autoFocus={autoFocus}
className={styles.select}
disabled={disabled}
form={form}
id={id}
@ -36,7 +63,7 @@ const Select = ({
selected={selected}
>
{children}
</select>
</StyledSelect>
</div>
);
};

View File

@ -1,28 +0,0 @@
.select {
composes: input from "../input/style.css";
/* select[multiple] is valid CSS syntax - not added to lint library yet */
/* stylelint-disable */
&[multiple] {
/* stylelint-enable */
padding-left: 0;
padding-right: 0;
& :global option {
padding-left: 15px;
padding-right: 15px;
width: 100%;
}
/* this doesn't seem to work, research further
&:-internal-list-box :global option:checked,
& :global option:checked {
background-color: white;
}
*/
}
}
.label {
composes: label from "../input/style.css";
}

View File

@ -1,19 +1,32 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const {
rndId
} = fns;
const {
default: styled
} = Styled;
const StyledTabs = styled.div`
font-size: 0;
&::after {
clear: both;
content: "";
display: table;
}
`;
const Tabs = ({
className,
children, // array of <Tab>
id,
id = rndId(),
name = '',
style
}) => {
const cn = classNames(
className,
styles.tabs
);
const _children = React.Children.map(children, (child, i) => {
return React.cloneElement(child, {
defaultChecked: i === 0,
@ -22,14 +35,14 @@ const Tabs = ({
});
return (
<div
className={cn}
<StyledTabs
className={className}
id={id}
role='tablist'
style={style}
>
{_children}
</div>
</StyledTabs>
);
};

View File

@ -1,46 +1,129 @@
const composers = require('../../../shared/composers');
const constants = require('../../../shared/constants');
const fns = require('../../../shared/functions');
const paramCase = require('param-case');
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const Styled = require('styled-components');
const {
moveZ
} = composers;
const {
boxes
} = constants;
const {
remcalc,
rndId
} = fns;
const {
default: styled
} = Styled;
const classNames = {
label: rndId(),
panel: rndId()
};
const StyledTab = styled.div`
display: inline;
`;
const StyledRadio = styled.input`
clip: rect(0 0 0 0);
height: 1px;
opacity: 0;
width: 1px;
${moveZ({
position: 'fixed',
amount: -1
})}
&:checked {
& + .${classNames.label} {
background: #FAFAFA;
border-bottom-width: 0;
padding-bottom: ${remcalc(11)};
${moveZ({
amount: 1
})}
}
& ~ .${classNames.panel} {
display: inline;
}
}
`;
const StyledLabel = styled.label`
background: #F2F2F2;
border: ${boxes.border.unchecked};
color: #646464;
display: inline-block;
font-size: ${remcalc(20)};
left: 1px;
margin-left: -1px;
padding: ${remcalc(10)};
position: relative;
vertical-align: bottom;
`;
const StyledPanel = styled.div`
display: inline-block;
height: 0;
overflow: hidden;
position: relative;
width: 0;
`;
const StyledContent = styled.div`
background: #FAFAFA;
border: ${boxes.border.unchecked};
box-sizing: border-box;
display: block;
float: left;
font-size: ${remcalc(16)};
margin-top: ${remcalc(-1)};
padding: ${remcalc('0 20')};
width: 100%;
`;
const Tab = ({
className,
children,
checked,
defaultChecked = true,
defaultChecked = false,
disabled = false,
id,
name,
title = '',
style
}) => {
const cn = classNames(
className,
styles.tab
);
const tabId = paramCase(title);
return (
<div className={cn}>
<input
<StyledTab className={className}>
<StyledRadio
checked={checked}
className={styles.radio_input}
defaultChecked={defaultChecked}
disabled={disabled}
id={tabId}
name={name}
type='radio'
/>
<label className={styles.label} htmlFor={tabId}>
<StyledLabel className={classNames.label} htmlFor={tabId}>
{title}
</label>
<div className={styles.panel}>
<div className={styles.content}>
</StyledLabel>
<StyledPanel className={classNames.panel}>
<StyledContent>
{children}
</div>
</div>
</div>
</StyledContent>
</StyledPanel>
</StyledTab>
);
};

View File

@ -1,48 +1,120 @@
// TODO: use a checkbox
const classNames = require('classnames');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const React = require('react');
const styles = require('./style.css');
const Styled = require('styled-components');
const {
boxes,
colors
} = constants;
const {
remcalc,
rndId
} = fns;
const {
default: styled
} = Styled;
const classNames = {
label: rndId()
};
const StyledLabel = styled.label`
border-radius: ${boxes.borderRadius};
color: #464646;
height: 2.5rem;
width: 110px;
`;
const StyledToggleLabel = styled.div`
background-color: #E6E6E6;
border: solid 1px #D8D8D8;
border-radius: ${boxes.borderRadius};
color: #000000;
height: ${remcalc(54)};
margin: 0.125rem;
padding: ${remcalc('12 12 12 0')};
position: relative;
text-align: right;
width: ${remcalc(106)};
&::before {
content: "Off";
font-family: inherit;
font-size: inherit;
font-weight: bold;
position: absolute;
right: 14px;
top: 13px;
}
&::after {
background-color: #FFFFFF;
border-radius: ${boxes.borderRadius};
content: "";
height: ${remcalc(46)};
left: 3px;
position: absolute;
top: 3px;
width: ${remcalc(46)};
}
`;
const StyledInput = styled.input`
display: none;
&:checked {
& + .${classNames.label} {
background: ${colors.confirmation};
border: ${boxes.border.confirmed};
color: #FFFFFF;
padding: ${remcalc('12 0 12 12')};
text-align: left;
&::before {
content: "On";
left: 14px;
right: auto;
}
&::after {
left: auto;
right: 3px;
}
}
}
`;
const Toggle = ({
checked = false,
checked,
className,
defaultChecked,
id = rndId(),
style
}) => {
const tgl = classNames(
className,
styles.tgl,
checked ? styles.on : styles.off,
);
const input = classNames(
className,
styles.input
);
const label = classNames(
className,
styles['tgl-label']
);
return (
<div className='' style={style}>
<label className={tgl} htmlFor='toggle' >
<input
checked={checked}
className={input}
id='toggle'
type='checkbox'
/>
<div className={label} />
</label>
</div>
<StyledLabel
className={className}
htmlFor={id}
style={style}
>
<StyledInput
checked={checked}
id={id}
type='checkbox'
/>
<StyledToggleLabel className={classNames.label} />
</StyledLabel>
);
};
Toggle.propTypes = {
checked: React.PropTypes.bool,
className: React.PropTypes.string,
defaultChecked: React.PropTypes.bool,
id: React.PropTypes.string,
style: React.PropTypes.object
};

View File

@ -1,83 +0,0 @@
/*
* - This can probably be achieved with flexbox so that we don't use any
* margins or paddings
* - We shouldn't use #FFFFFF but a variation of it to have less contrast
*/
~boxes: "../../shared/constants.js";
~colors: "../../shared/constants.js";
:root {
--background-confirmed: ~colors.confirmation;
--border-confirmed: ~boxes.border.confirmed;
--border-unchecked: ~boxes.border.unchecked;
--border-radius: remcalc(~boxes.borderRadius);
--bottom-shaddow: ~boxes.bottomShaddow;
}
.tgl {
border-radius: var(--border-radius);
color: #464646;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
height: 2.5rem;
width: 110px;
}
.tgl-label {
background-color: #E6E6E6;
border: solid 1px #D8D8D8;
border-radius: var(--border-radius);
color: #000000;
height: remcalc(54);
margin: 0.125rem;
padding: remcalc(12 12 12 0);
position: relative;
text-align: right;
width: remcalc(106);
&::before {
content: "Off";
font-family: inherit;
font-size: inherit;
font-weight: bold;
position: absolute;
right: 14px;
top: 13px;
}
&::after {
background-color: #FFFFFF;
border-radius: var(--border-radius);
content: "";
height: remcalc(46);
left: 3px;
position: absolute;
top: 3px;
width: remcalc(46);
}
}
.input {
display: none;
&:checked {
& + .tgl-label {
background: var(--background-confirmed);
border: var(--border-confirmed);
color: #FFFFFF;
padding: remcalc(12 0 12 12);
text-align: left;
&::before {
content: "On";
left: 14px;
right: auto;
}
&::after {
left: auto;
right: 3px;
}
}
}
}

View File

@ -1,39 +1,84 @@
const classNames = require('classnames');
const React = require('react');
const styles = require('./style.css');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const {
boxes
} = constants;
const {
rndId
} = fns;
const {
default: styled,
} = Styled;
const classNames = {
content: rndId()
};
const StyledInput = styled.input`
display: none;
visibility: hidden;
&:checked {
& ~ .${classNames.content} {
border: ${boxes.border.checked};
}
}
&:disabled {
& ~ .${classNames.content} {
cursor: not-allowed;
filter: grayscale(80%);
opacity: 0.4;
}
}
`;
const StyledContent = styled.div`
border: ${boxes.border.unchecked};
border-radius: 4px;
cursor: pointer;
padding: remcalc(36);
& img {
max-width: 100%;
}
`;
const Widget = ({
checked = false,
children,
className,
disabled = false,
id,
name,
selectable = 'single',
style,
value = name
}) => {
const cn = classNames(
className,
styles.widget
);
const type = selectable === 'single' ? 'radio' : 'checkbox';
return (
<label className={cn} htmlFor={value}>
<input
<label
className={className}
htmlFor={value}
id={id}
>
<StyledInput
checked={checked}
className={styles.input}
disabled={disabled}
id={value}
name={name}
type={type}
value={value}
/>
<div className={styles.content}>
<StyledContent className={classNames.content}>
{children}
</div>
</StyledContent>
</label>
);
};
@ -43,6 +88,7 @@ Widget.propTypes = {
children: React.PropTypes.object,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
id: React.PropTypes.string,
name: React.PropTypes.string,
selectable: React.PropTypes.string,
style: React.PropTypes.object,

View File

@ -1,36 +0,0 @@
~boxes: "../../shared/constants.js";
:root {
--border-checked: ~boxes.border.checked;
--border-unchecked: ~boxes.border.unchecked;
}
.content {
border: var(--border-unchecked);
border-radius: 4px;
cursor: pointer;
padding: remcalc(36);
& img {
max-width: 100%;
}
}
.input {
display: none;
visibility: hidden;
&:checked {
& ~ .content {
border: var(--border-checked);
}
}
&:disabled {
& ~ .content {
cursor: not-allowed;
filter: grayscale(80%);
opacity: 0.4;
}
}
}

View File

@ -1,31 +0,0 @@
module.exports = {
'Getting Started': require('./getting-started.md'),
Guidelines: {
Overview: require('./guidelines/overview.md'),
Layout: require('./guidelines/layout.md')
},
Components: {
Avatar: require('./components/avatar/readme.md'),
Base: require('./components/base/readme.md'),
Container: require('./components/container/readme.md'),
Row: require('./components/row/readme.md'),
Input: require('./components/input/readme.md'),
Icon: require('./components/icon/readme.md'),
Radio: require('./components/radio/readme.md'),
'Radio Group': require('./components/radio-group/readme.md'),
Select: require('./components/select/readme.md'),
Column: require('./components/column/readme.md'),
Button: require('./components/button/readme.md'),
'Button Icon': require('./components/button-icon/readme.md'),
'Range Slider': require('./components/range-slider/readme.md'),
Toggle: require('./components/toggle/readme.md'),
Notificaton: require('./components/notification/readme.md'),
Checkbox: require('./components/checkbox/readme.md'),
Tab: require('./components/tabs/tab/readme.md'),
Tabs: require('./components/tabs/readme.md'),
Widget: require('./components/widget/readme.md'),
Pagination: require('./components/pagination/readme.md'),
Modal: require('./components/modal/readme.md')
},
FAQ: require('./faq.md')
};

Some files were not shown because too many files have changed in this diff Show More