├── .gitignore
├── README
├── deploy.sh
├── favicon.ico
├── index.html
├── package.json
└── src
├── App.js
├── Box.js
├── Joystick.js
├── Pannable.js
├── Pannable.service.js
├── index.css
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Joystick
2 |
3 | Proof of concept for in browser animation rigging.
4 |
5 | npm start
6 | npm run build
7 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit #abort if any command fails
3 |
4 | main() {
5 | deploy_directory=${GIT_DEPLOY_DIR:-build}
6 | deploy_branch=${GIT_DEPLOY_BRANCH:-gh-pages}
7 |
8 | #if no user identity is already set in the current git environment, use this:
9 | default_username=${GIT_DEPLOY_USERNAME:-winkerVSbecks}
10 | default_email=${GIT_DEPLOY_EMAIL:-varunvachhar@gmail.com}
11 |
12 | #repository to deploy to. must be readable and writable.
13 | repo=${GIT_DEPLOY_REPO:-git@github.com:winkerVSbecks/joystick.git}
14 |
15 | #append commit hash to the end of message by default
16 | append_hash=true
17 |
18 | # Parse arg flags
19 | while : ; do
20 | if [[ $1 = "-v" || $1 = "--verbose" ]]; then
21 | verbose=true
22 | shift
23 | elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
24 | allow_empty=true
25 | shift
26 | elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
27 | commit_message=$2
28 | shift 2
29 | elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
30 | append_hash=false
31 | shift
32 | else
33 | break
34 | fi
35 | done
36 |
37 | enable_expanded_output
38 |
39 | if ! git diff --exit-code --quiet --cached; then
40 | echo Aborting due to uncommitted changes in the index >&2
41 | return 1
42 | fi
43 |
44 | commit_title=`git log -n 1 --format="%s" HEAD`
45 | commit_hash=` git log -n 1 --format="%H" HEAD`
46 |
47 | #default commit message uses last title if a custom one is not supplied
48 | if [[ -z $commit_message ]]; then
49 | commit_message="publish: $commit_title"
50 | fi
51 |
52 | #append hash to commit message unless no hash flag was found
53 | if [ $append_hash = true ]; then
54 | commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
55 | fi
56 |
57 | previous_branch=`git rev-parse --abbrev-ref HEAD`
58 |
59 | if [ ! -d "$deploy_directory" ]; then
60 | echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
61 | return 1
62 | fi
63 |
64 | # must use short form of flag in ls for compatibility with OS X and BSD
65 | if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
66 | echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
67 | return 1
68 | fi
69 |
70 | if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
71 | # deploy_branch exists in $repo; make sure we have the latest version
72 |
73 | disable_expanded_output
74 | git fetch --force $repo $deploy_branch:$deploy_branch
75 | enable_expanded_output
76 | fi
77 |
78 | # check if deploy_branch exists locally
79 | if git show-ref --verify --quiet "refs/heads/$deploy_branch"
80 | then incremental_deploy
81 | else initial_deploy
82 | fi
83 |
84 | restore_head
85 | }
86 |
87 | initial_deploy() {
88 | git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
89 | git --work-tree "$deploy_directory" add --all
90 | commit+push
91 | }
92 |
93 | incremental_deploy() {
94 | #make deploy_branch the current branch
95 | git symbolic-ref HEAD refs/heads/$deploy_branch
96 | #put the previously committed contents of deploy_branch into the index
97 | git --work-tree "$deploy_directory" reset --mixed --quiet
98 | git --work-tree "$deploy_directory" add --all
99 |
100 | set +o errexit
101 | diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
102 | set -o errexit
103 | case $diff in
104 | 0) echo No changes to files in $deploy_directory. Skipping commit.;;
105 | 1) commit+push;;
106 | *)
107 | echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2
108 | return $diff
109 | ;;
110 | esac
111 | }
112 |
113 | commit+push() {
114 | set_user_id
115 | git --work-tree "$deploy_directory" commit -m "$commit_message"
116 |
117 | disable_expanded_output
118 | #--quiet is important here to avoid outputting the repo URL, which may contain a secret token
119 | git push --quiet $repo $deploy_branch
120 | enable_expanded_output
121 | }
122 |
123 | #echo expanded commands as they are executed (for debugging)
124 | enable_expanded_output() {
125 | if [ $verbose ]; then
126 | set -o xtrace
127 | set +o verbose
128 | fi
129 | }
130 |
131 | #this is used to avoid outputting the repo URL, which may contain a secret token
132 | disable_expanded_output() {
133 | if [ $verbose ]; then
134 | set +o xtrace
135 | set -o verbose
136 | fi
137 | }
138 |
139 | set_user_id() {
140 | if [[ -z `git config user.name` ]]; then
141 | git config user.name "$default_username"
142 | fi
143 | if [[ -z `git config user.email` ]]; then
144 | git config user.email "$default_email"
145 | fi
146 | }
147 |
148 | restore_head() {
149 | if [[ $previous_branch = "HEAD" ]]; then
150 | #we weren't on any branch before, so just set HEAD back to the commit it was on
151 | git update-ref --no-deref HEAD $commit_hash $deploy_branch
152 | else
153 | git symbolic-ref HEAD refs/heads/$previous_branch
154 | fi
155 |
156 | git reset --mixed
157 | }
158 |
159 | filter() {
160 | sed -e "s|$repo|\$repo|g"
161 | }
162 |
163 | sanitize() {
164 | "$@" 2> >(filter 1>&2) | filter
165 | }
166 |
167 | [[ $1 = --source-only ]] || main "$@"
168 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/winkerVSbecks/joystick/3889d149477a50e9d54c4bffc6439e06d8f92668/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Joystick
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "joystick",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "babel-eslint": "^6.1.2",
7 | "eslint": "^3.3.1",
8 | "eslint-plugin-flowtype": "^2.11.0",
9 | "eslint-plugin-import": "^1.13.0",
10 | "eslint-plugin-jsx-a11y": "^2.1.0",
11 | "eslint-plugin-react": "^6.1.2",
12 | "react-scripts": "0.2.1"
13 | },
14 | "dependencies": {
15 | "lodash.debounce": "^4.0.8",
16 | "react": "^15.2.1",
17 | "react-dom": "^15.2.1",
18 | "react-motion": "^0.4.4",
19 | "recompose": "^0.20.2"
20 | },
21 | "scripts": {
22 | "start": "react-scripts start",
23 | "build": "react-scripts build",
24 | "eject": "react-scripts eject",
25 | "deploy": "bash deploy.sh"
26 | },
27 | "eslintConfig": {
28 | "extends": "./node_modules/react-scripts/config/eslint.js"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { compose, withState, lifecycle } from 'recompose';
3 | import './index.css';
4 | import Joystick from './Joystick';
5 | import Box from './Box';
6 | import debounce from 'lodash.debounce';
7 |
8 | const size = 128;
9 |
10 | const styles = {
11 | borderRadius: 6,
12 | border: '1px solid #444',
13 | background: `url("data:image/svg+xml;utf8,")`,
14 | backgroundSize: '7.5px 6px',
15 | };
16 |
17 | function App({
18 | size: { w, h },
19 | joyStick1, setJoyStick1,
20 | joyStick2, setJoyStick2,
21 | }) {
22 | return (
23 |
24 |
25 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
{ JSON.stringify(joyStick2, round, 2) }
46 |
47 |
48 |
{ JSON.stringify(joyStick1, round, 2) }
49 |
50 |
51 |
52 |
53 |
55 |
57 |
58 |
59 |
60 | );
61 | }
62 |
63 | const enhance = compose(
64 | withState('size', 'setSize', { w: 0, h: 0 }),
65 | withState('joyStick1', 'setJoyStick1', { x: 0, y: 0 }),
66 | withState('joyStick2', 'setJoyStick2', { x: 0, y: 0 }),
67 | lifecycle({
68 | componentWillMount(e) {
69 | window.addEventListener('resize', () => {
70 | this.props.setSize({
71 | w: window.innerWidth,
72 | h: window.innerHeight,
73 | });
74 | })
75 | }
76 | })
77 | );
78 |
79 | export default enhance(App);
80 |
81 | function round(key, val) {
82 | return val.toFixed ? Number(val.toFixed(3)) : val;
83 | }
84 |
--------------------------------------------------------------------------------
/src/Box.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function Box({
4 | x = 0, y = 0,
5 | width, height,
6 | className,
7 | children,
8 | style,
9 | }) {
10 | const baseStyles = {
11 | width,
12 | height,
13 | transformOrigin: '50% 50%',
14 | willChange: 'transform, width, height',
15 | transform: `translate3d(${ x }px, ${ y }px, 0)`,
16 | };
17 |
18 | return (
19 |
20 | { children }
21 |
22 | );
23 | }
24 |
25 | Box.propTypes = {
26 | x: React.PropTypes.number,
27 | y: React.PropTypes.number,
28 | width: React.PropTypes.number.isRequired,
29 | height: React.PropTypes.number.isRequired,
30 | style: React.PropTypes.object,
31 | className: React.PropTypes.string,
32 | children: React.PropTypes.node,
33 | };
34 |
35 | export default Box;
36 |
--------------------------------------------------------------------------------
/src/Joystick.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Box from './Box';
3 | import Pannable from './Pannable';
4 |
5 | const styles = {
6 | container: {
7 | borderColor: '#444',
8 | borderRadius: 8,
9 | borderWidth: 1,
10 | borderStyle: 'solid',
11 | cursor: 'pointer',
12 | },
13 | pad: {
14 | borderColor: '#444',
15 | borderRadius: '50%',
16 | borderWidth: 1,
17 | opacity: 0.9,
18 | borderStyle: 'solid',
19 | background: `url("data:image/svg+xml;utf8,")`,
20 | backgroundSize: '7.5px 6px',
21 | backgroundColor: '#fff',
22 | }
23 | };
24 |
25 | function Joystick({ w, h, onChange }) {
26 | return (
27 |
28 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 | );
42 | }
43 |
44 | Joystick.propTypes = {
45 | w: React.PropTypes.number.isRequired,
46 | h: React.PropTypes.number.isRequired,
47 | onChange: React.PropTypes.func.isRequired,
48 | };
49 |
50 | export default Joystick;
51 |
--------------------------------------------------------------------------------
/src/Pannable.js:
--------------------------------------------------------------------------------
1 | import { compose, withState, withHandlers } from 'recompose';
2 | import React from 'react';
3 | import * as pannableService from './Pannable.service';
4 |
5 | function Pannable({ onPanStart, onPan, onPanEnd, pan, children }) {
6 | return (
7 |
15 | {
16 | React.cloneElement(children, { ...pan })
17 | }
18 |
19 | );
20 | }
21 |
22 | Pannable.propTypes = {
23 | size: React.PropTypes.shape({
24 | w: React.PropTypes.number,
25 | h: React.PropTypes.number,
26 | }).isRequired,
27 | onPan: React.PropTypes.func.isRequired,
28 | onPanStart: React.PropTypes.func.isRequired,
29 | onPanEnd: React.PropTypes.func.isRequired,
30 | children: React.PropTypes.node.isRequired,
31 | onChange: React.PropTypes.func.isRequired,
32 | pan: React.PropTypes.shape({
33 | x: React.PropTypes.number,
34 | y: React.PropTypes.number,
35 | xNorm: React.PropTypes.number,
36 | yNorm: React.PropTypes.number,
37 | }).isRequired,
38 | };
39 |
40 | const enhance = compose(
41 | withState('offset', 'setOffset', { top: 0, left: 0 }),
42 | withState('pan', 'setPan', { x: 0, y: 0 }),
43 | withHandlers({
44 | onPanStart: pannableService.onPanStart,
45 | onPan: pannableService.onPan,
46 | onPanEnd: pannableService.onPanEnd,
47 | })
48 | );
49 |
50 | export default enhance(Pannable);
51 |
--------------------------------------------------------------------------------
/src/Pannable.service.js:
--------------------------------------------------------------------------------
1 | export function onPanStart(props) {
2 | return e => {
3 | if (e.type === 'dragstart') {
4 | e.dataTransfer.setDragImage(getImage(), 0, 0);
5 | }
6 |
7 | const boundingRect = e.currentTarget.parentNode.getBoundingClientRect();
8 | props.setOffset(boundingRect);
9 | };
10 | }
11 |
12 | export function onPan(props) {
13 | return e => {
14 | const pan = getPan(e, props.offset, props.size);
15 | props.setPan(pan.raw);
16 | props.onChange(pan.normalized);
17 | };
18 | }
19 |
20 | export function onPanEnd(props) {
21 | return e => {
22 | props.setPan(
23 | { x: 0, y: 0 },
24 | () => props.onChange({ x: 0, y: 0 })
25 | );
26 | };
27 | }
28 |
29 | function getPan(e, offset, size) {
30 | if (e.type === 'drag') {
31 | return withOffset(offset, size, { x: e.clientX, y: e.clientY });
32 | }
33 |
34 | const touch = e.targetTouches[0] ? e.targetTouches[0] : e.changedTouches[0];
35 | return withOffset(offset, size, { x: touch.clientX, y: touch.clientY });
36 | }
37 |
38 | function withOffset({ top, left, width, height }, { w, h }, { x, y }) {
39 | const panX = constrainedTo(width, w / 4, x - (left + width / 2));
40 | const panY = constrainedTo(height, h / 4, y - (top + height / 2));
41 | return {
42 | raw: {
43 | x: panX,
44 | y: panY,
45 | },
46 | normalized: {
47 | x: panX / (width * 0.5 - w / 4),
48 | y: panY / (height * 0.5 - h / 4),
49 | },
50 | };
51 | }
52 |
53 | function constrainedTo(delta, size, value) {
54 | return Math.min( Math.max(-delta / 2 + size, value), delta / 2 - size);
55 | }
56 |
57 | function getImage() {
58 | let img = new Image();
59 | img.src = 'data:image/gif;base64' +
60 | ',R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
61 | return img;
62 | }
63 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | .vh-100 { height: 100vh }
8 | .bg-white { background-color: #fff }
9 | .cursor { cursor: move }
10 | .monospace { font-family: monospace }
11 |
12 | .h1{ font-size: 2rem }
13 | .h2{ font-size: 1.5rem }
14 | .h3{ font-size: 1.25rem }
15 | .h4{ font-size: 1rem }
16 | .h5{ font-size: .875rem }
17 | .h6{ font-size: .75rem }
18 |
19 | .font-family-inherit{ font-family:inherit }
20 | .font-size-inherit{ font-size:inherit }
21 | .text-decoration-none{ text-decoration:none }
22 |
23 | .bold{ font-weight: bold; font-weight: bold }
24 | .regular{ font-weight:normal }
25 | .italic{ font-style:italic }
26 | .caps{ text-transform:uppercase; letter-spacing: .2em; }
27 |
28 | .left-align{ text-align:left }
29 | .center{ text-align:center }
30 | .right-align{ text-align:right }
31 | .justify{ text-align:justify }
32 |
33 | .nowrap{ white-space:nowrap }
34 | .break-word{ word-wrap:break-word }
35 |
36 | .line-height-1{ line-height: 1 }
37 | .line-height-2{ line-height: 1.125 }
38 | .line-height-3{ line-height: 1.25 }
39 | .line-height-4{ line-height: 1.5 }
40 |
41 | .list-style-none{ list-style:none }
42 | .underline{ text-decoration:underline }
43 |
44 | .truncate{
45 | max-width:100%;
46 | overflow:hidden;
47 | text-overflow:ellipsis;
48 | white-space:nowrap;
49 | }
50 |
51 | .list-reset{
52 | list-style:none;
53 | padding-left:0;
54 | }
55 |
56 | .inline{ display:inline }
57 | .block{ display:block }
58 | .inline-block{ display:inline-block }
59 | .table{ display:table }
60 | .table-cell{ display:table-cell }
61 |
62 | .overflow-hidden{ overflow:hidden }
63 | .overflow-scroll{ overflow:scroll }
64 | .overflow-auto{ overflow:auto }
65 |
66 | .clearfix:before,
67 | .clearfix:after{
68 | content:" ";
69 | display:table
70 | }
71 | .clearfix:after{ clear:both }
72 |
73 | .left{ float:left }
74 | .right{ float:right }
75 |
76 | .fit{ max-width:100% }
77 |
78 | .max-width-1{ max-width: 24rem }
79 | .max-width-2{ max-width: 32rem }
80 | .max-width-3{ max-width: 48rem }
81 | .max-width-4{ max-width: 64rem }
82 |
83 | .border-box{ box-sizing:border-box }
84 |
85 | .align-baseline{ vertical-align:baseline }
86 | .align-top{ vertical-align:top }
87 | .align-middle{ vertical-align:middle }
88 | .align-bottom{ vertical-align:bottom }
89 |
90 | .m0{ margin:0 }
91 | .mt0{ margin-top:0 }
92 | .mr0{ margin-right:0 }
93 | .mb0{ margin-bottom:0 }
94 | .ml0{ margin-left:0 }
95 | .mx0{ margin-left:0; margin-right:0 }
96 | .my0{ margin-top:0; margin-bottom:0 }
97 |
98 | .m1{ margin: .5rem }
99 | .mt1{ margin-top: .5rem }
100 | .mr1{ margin-right: .5rem }
101 | .mb1{ margin-bottom: .5rem }
102 | .ml1{ margin-left: .5rem }
103 | .mx1{ margin-left: .5rem; margin-right: .5rem }
104 | .my1{ margin-top: .5rem; margin-bottom: .5rem }
105 |
106 | .m2{ margin: 1rem }
107 | .mt2{ margin-top: 1rem }
108 | .mr2{ margin-right: 1rem }
109 | .mb2{ margin-bottom: 1rem }
110 | .ml2{ margin-left: 1rem }
111 | .mx2{ margin-left: 1rem; margin-right: 1rem }
112 | .my2{ margin-top: 1rem; margin-bottom: 1rem }
113 |
114 | .m3{ margin: 2rem }
115 | .mt3{ margin-top: 2rem }
116 | .mr3{ margin-right: 2rem }
117 | .mb3{ margin-bottom: 2rem }
118 | .ml3{ margin-left: 2rem }
119 | .mx3{ margin-left: 2rem; margin-right: 2rem }
120 | .my3{ margin-top: 2rem; margin-bottom: 2rem }
121 |
122 | .m4{ margin: 4rem }
123 | .mt4{ margin-top: 4rem }
124 | .mr4{ margin-right: 4rem }
125 | .mb4{ margin-bottom: 4rem }
126 | .ml4{ margin-left: 4rem }
127 | .mx4{ margin-left: 4rem; margin-right: 4rem }
128 | .my4{ margin-top: 4rem; margin-bottom: 4rem }
129 |
130 | .mxn1{ margin-left: -.5rem; margin-right: -.5rem; }
131 | .mxn2{ margin-left: -1rem; margin-right: -1rem; }
132 | .mxn3{ margin-left: -2rem; margin-right: -2rem; }
133 | .mxn4{ margin-left: -4rem; margin-right: -4rem; }
134 |
135 | .ml-auto{ margin-left:auto }
136 | .mr-auto{ margin-right:auto }
137 | .mx-auto{ margin-left:auto; margin-right:auto; }
138 |
139 | .p0{ padding:0 }
140 | .pt0{ padding-top:0 }
141 | .pr0{ padding-right:0 }
142 | .pb0{ padding-bottom:0 }
143 | .pl0{ padding-left:0 }
144 | .px0{ padding-left:0; padding-right:0 }
145 | .py0{ padding-top:0; padding-bottom:0 }
146 |
147 | .p1{ padding: .5rem }
148 | .pt1{ padding-top: .5rem }
149 | .pr1{ padding-right: .5rem }
150 | .pb1{ padding-bottom: .5rem }
151 | .pl1{ padding-left: .5rem }
152 | .py1{ padding-top: .5rem; padding-bottom: .5rem }
153 | .px1{ padding-left: .5rem; padding-right: .5rem }
154 |
155 | .p2{ padding: 1rem }
156 | .pt2{ padding-top: 1rem }
157 | .pr2{ padding-right: 1rem }
158 | .pb2{ padding-bottom: 1rem }
159 | .pl2{ padding-left: 1rem }
160 | .py2{ padding-top: 1rem; padding-bottom: 1rem }
161 | .px2{ padding-left: 1rem; padding-right: 1rem }
162 |
163 | .p3{ padding: 2rem }
164 | .pt3{ padding-top: 2rem }
165 | .pr3{ padding-right: 2rem }
166 | .pb3{ padding-bottom: 2rem }
167 | .pl3{ padding-left: 2rem }
168 | .py3{ padding-top: 2rem; padding-bottom: 2rem }
169 | .px3{ padding-left: 2rem; padding-right: 2rem }
170 |
171 | .p4{ padding: 4rem }
172 | .pt4{ padding-top: 4rem }
173 | .pr4{ padding-right: 4rem }
174 | .pb4{ padding-bottom: 4rem }
175 | .pl4{ padding-left: 4rem }
176 | .py4{ padding-top: 4rem; padding-bottom: 4rem }
177 | .px4{ padding-left: 4rem; padding-right: 4rem }
178 |
179 | .col{
180 | float:left;
181 | box-sizing:border-box;
182 | }
183 |
184 | .col-right{
185 | float:right;
186 | box-sizing:border-box;
187 | }
188 |
189 | .col-1{
190 | width:8.33333%;
191 | }
192 |
193 | .col-2{
194 | width:16.66667%;
195 | }
196 |
197 | .col-3{
198 | width:25%;
199 | }
200 |
201 | .col-4{
202 | width:33.33333%;
203 | }
204 |
205 | .col-5{
206 | width:41.66667%;
207 | }
208 |
209 | .col-6{
210 | width:50%;
211 | }
212 |
213 | .col-7{
214 | width:58.33333%;
215 | }
216 |
217 | .col-8{
218 | width:66.66667%;
219 | }
220 |
221 | .col-9{
222 | width:75%;
223 | }
224 |
225 | .col-10{
226 | width:83.33333%;
227 | }
228 |
229 | .col-11{
230 | width:91.66667%;
231 | }
232 |
233 | .col-12{
234 | width:100%;
235 | }
236 | @media (min-width: 40em){
237 |
238 | .sm-col{
239 | float:left;
240 | box-sizing:border-box;
241 | }
242 |
243 | .sm-col-right{
244 | float:right;
245 | box-sizing:border-box;
246 | }
247 |
248 | .sm-col-1{
249 | width:8.33333%;
250 | }
251 |
252 | .sm-col-2{
253 | width:16.66667%;
254 | }
255 |
256 | .sm-col-3{
257 | width:25%;
258 | }
259 |
260 | .sm-col-4{
261 | width:33.33333%;
262 | }
263 |
264 | .sm-col-5{
265 | width:41.66667%;
266 | }
267 |
268 | .sm-col-6{
269 | width:50%;
270 | }
271 |
272 | .sm-col-7{
273 | width:58.33333%;
274 | }
275 |
276 | .sm-col-8{
277 | width:66.66667%;
278 | }
279 |
280 | .sm-col-9{
281 | width:75%;
282 | }
283 |
284 | .sm-col-10{
285 | width:83.33333%;
286 | }
287 |
288 | .sm-col-11{
289 | width:91.66667%;
290 | }
291 |
292 | .sm-col-12{
293 | width:100%;
294 | }
295 |
296 | }
297 | @media (min-width: 52em){
298 |
299 | .md-col{
300 | float:left;
301 | box-sizing:border-box;
302 | }
303 |
304 | .md-col-right{
305 | float:right;
306 | box-sizing:border-box;
307 | }
308 |
309 | .md-col-1{
310 | width:8.33333%;
311 | }
312 |
313 | .md-col-2{
314 | width:16.66667%;
315 | }
316 |
317 | .md-col-3{
318 | width:25%;
319 | }
320 |
321 | .md-col-4{
322 | width:33.33333%;
323 | }
324 |
325 | .md-col-5{
326 | width:41.66667%;
327 | }
328 |
329 | .md-col-6{
330 | width:50%;
331 | }
332 |
333 | .md-col-7{
334 | width:58.33333%;
335 | }
336 |
337 | .md-col-8{
338 | width:66.66667%;
339 | }
340 |
341 | .md-col-9{
342 | width:75%;
343 | }
344 |
345 | .md-col-10{
346 | width:83.33333%;
347 | }
348 |
349 | .md-col-11{
350 | width:91.66667%;
351 | }
352 |
353 | .md-col-12{
354 | width:100%;
355 | }
356 |
357 | }
358 | @media (min-width: 64em){
359 |
360 | .lg-col{
361 | float:left;
362 | box-sizing:border-box;
363 | }
364 |
365 | .lg-col-right{
366 | float:right;
367 | box-sizing:border-box;
368 | }
369 |
370 | .lg-col-1{
371 | width:8.33333%;
372 | }
373 |
374 | .lg-col-2{
375 | width:16.66667%;
376 | }
377 |
378 | .lg-col-3{
379 | width:25%;
380 | }
381 |
382 | .lg-col-4{
383 | width:33.33333%;
384 | }
385 |
386 | .lg-col-5{
387 | width:41.66667%;
388 | }
389 |
390 | .lg-col-6{
391 | width:50%;
392 | }
393 |
394 | .lg-col-7{
395 | width:58.33333%;
396 | }
397 |
398 | .lg-col-8{
399 | width:66.66667%;
400 | }
401 |
402 | .lg-col-9{
403 | width:75%;
404 | }
405 |
406 | .lg-col-10{
407 | width:83.33333%;
408 | }
409 |
410 | .lg-col-11{
411 | width:91.66667%;
412 | }
413 |
414 | .lg-col-12{
415 | width:100%;
416 | }
417 |
418 | }
419 | .flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
420 |
421 | @media (min-width: 40em){
422 | .sm-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
423 | }
424 |
425 | @media (min-width: 52em){
426 | .md-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
427 | }
428 |
429 | @media (min-width: 64em){
430 | .lg-flex{ display:-webkit-box; display:-webkit-flex; display:-ms-flexbox; display:flex }
431 | }
432 |
433 | .flex-column{ -webkit-box-orient:vertical; -webkit-box-direction:normal; -webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column }
434 | .flex-wrap{ -webkit-flex-wrap:wrap; -ms-flex-wrap:wrap; flex-wrap:wrap }
435 |
436 | .items-start{ -webkit-box-align:start; -webkit-align-items:flex-start; -ms-flex-align:start; -ms-grid-row-align:flex-start; align-items:flex-start }
437 | .items-end{ -webkit-box-align:end; -webkit-align-items:flex-end; -ms-flex-align:end; -ms-grid-row-align:flex-end; align-items:flex-end }
438 | .items-center{ -webkit-box-align:center; -webkit-align-items:center; -ms-flex-align:center; -ms-grid-row-align:center; align-items:center }
439 | .items-baseline{ -webkit-box-align:baseline; -webkit-align-items:baseline; -ms-flex-align:baseline; -ms-grid-row-align:baseline; align-items:baseline }
440 | .items-stretch{ -webkit-box-align:stretch; -webkit-align-items:stretch; -ms-flex-align:stretch; -ms-grid-row-align:stretch; align-items:stretch }
441 |
442 | .self-start{ -webkit-align-self:flex-start; -ms-flex-item-align:start; align-self:flex-start }
443 | .self-end{ -webkit-align-self:flex-end; -ms-flex-item-align:end; align-self:flex-end }
444 | .self-center{ -webkit-align-self:center; -ms-flex-item-align:center; align-self:center }
445 | .self-baseline{ -webkit-align-self:baseline; -ms-flex-item-align:baseline; align-self:baseline }
446 | .self-stretch{ -webkit-align-self:stretch; -ms-flex-item-align:stretch; align-self:stretch }
447 |
448 | .justify-start{ -webkit-box-pack:start; -webkit-justify-content:flex-start; -ms-flex-pack:start; justify-content:flex-start }
449 | .justify-end{ -webkit-box-pack:end; -webkit-justify-content:flex-end; -ms-flex-pack:end; justify-content:flex-end }
450 | .justify-center{ -webkit-box-pack:center; -webkit-justify-content:center; -ms-flex-pack:center; justify-content:center }
451 | .justify-between{ -webkit-box-pack:justify; -webkit-justify-content:space-between; -ms-flex-pack:justify; justify-content:space-between }
452 | .justify-around{ -webkit-justify-content:space-around; -ms-flex-pack:distribute; justify-content:space-around }
453 |
454 | .content-start{ -webkit-align-content:flex-start; -ms-flex-line-pack:start; align-content:flex-start }
455 | .content-end{ -webkit-align-content:flex-end; -ms-flex-line-pack:end; align-content:flex-end }
456 | .content-center{ -webkit-align-content:center; -ms-flex-line-pack:center; align-content:center }
457 | .content-between{ -webkit-align-content:space-between; -ms-flex-line-pack:justify; align-content:space-between }
458 | .content-around{ -webkit-align-content:space-around; -ms-flex-line-pack:distribute; align-content:space-around }
459 | .content-stretch{ -webkit-align-content:stretch; -ms-flex-line-pack:stretch; align-content:stretch }
460 | .flex-auto{
461 | -webkit-box-flex:1;
462 | -webkit-flex:1 1 auto;
463 | -ms-flex:1 1 auto;
464 | flex:1 1 auto;
465 | min-width:0;
466 | min-height:0;
467 | }
468 | .flex-none{ -webkit-box-flex:0; -webkit-flex:none; -ms-flex:none; flex:none }
469 |
470 | .order-0{ -webkit-box-ordinal-group:1; -webkit-order:0; -ms-flex-order:0; order:0 }
471 | .order-1{ -webkit-box-ordinal-group:2; -webkit-order:1; -ms-flex-order:1; order:1 }
472 | .order-2{ -webkit-box-ordinal-group:3; -webkit-order:2; -ms-flex-order:2; order:2 }
473 | .order-3{ -webkit-box-ordinal-group:4; -webkit-order:3; -ms-flex-order:3; order:3 }
474 | .order-last{ -webkit-box-ordinal-group:100000; -webkit-order:99999; -ms-flex-order:99999; order:99999 }
475 |
476 | .relative{ position:relative }
477 | .absolute{ position:absolute }
478 | .fixed{ position:fixed }
479 |
480 | .top-0{ top:0 }
481 | .right-0{ right:0 }
482 | .bottom-0{ bottom:0 }
483 | .left-0{ left:0 }
484 |
485 | .z1{ z-index: 1 }
486 | .z2{ z-index: 2 }
487 | .z3{ z-index: 3 }
488 | .z4{ z-index: 4 }
489 |
490 | .border{
491 | border-style:solid;
492 | border-width: 1px;
493 | }
494 |
495 | .border-top{
496 | border-top-style:solid;
497 | border-top-width: 1px;
498 | }
499 |
500 | .border-right{
501 | border-right-style:solid;
502 | border-right-width: 1px;
503 | }
504 |
505 | .border-bottom{
506 | border-bottom-style:solid;
507 | border-bottom-width: 1px;
508 | }
509 |
510 | .border-left{
511 | border-left-style:solid;
512 | border-left-width: 1px;
513 | }
514 |
515 | .border-none{ border:0 }
516 |
517 | .rounded{ border-radius: 3px }
518 | .circle{ border-radius:50% }
519 |
520 | .rounded-top{ border-radius: 3px 3px 0 0 }
521 | .rounded-right{ border-radius: 0 3px 3px 0 }
522 | .rounded-bottom{ border-radius: 0 0 3px 3px }
523 | .rounded-left{ border-radius: 3px 0 0 3px }
524 |
525 | .not-rounded{ border-radius:0 }
526 |
527 | .hide{
528 | position:absolute !important;
529 | height:1px;
530 | width:1px;
531 | overflow:hidden;
532 | clip:rect(1px, 1px, 1px, 1px);
533 | }
534 |
535 | @media (max-width: 40em){
536 | .xs-hide{ display:none !important }
537 | }
538 |
539 | @media (min-width: 40em) and (max-width: 52em){
540 | .sm-hide{ display:none !important }
541 | }
542 |
543 | @media (min-width: 52em) and (max-width: 64em){
544 | .md-hide{ display:none !important }
545 | }
546 |
547 | @media (min-width: 64em){
548 | .lg-hide{ display:none !important }
549 | }
550 |
551 | .display-none{ display:none !important }
552 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
11 | document.ontouchmove = function(event) {
12 | event.preventDefault();
13 | };
14 |
--------------------------------------------------------------------------------