├── .dockerignore
├── .env
├── .eslintignore
├── .eslintrc
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── docker-compose.yml
├── jsconfig.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── App.js
├── assets
│ ├── fonts
│ │ └── OpenSans
│ │ │ ├── OpenSans-Bold.ttf
│ │ │ ├── OpenSans-ExtraBold.ttf
│ │ │ ├── OpenSans-Light.ttf
│ │ │ ├── OpenSans-Regular.ttf
│ │ │ └── OpenSans-SemiBold.ttf
│ └── images
│ │ ├── clipboard.svg
│ │ ├── gitcommand.png
│ │ ├── github-green.svg
│ │ └── github.svg
├── components
│ ├── footer.js
│ ├── index.js
│ ├── nav.js
│ └── toggle.js
├── data
│ ├── index.js
│ ├── primary-options.js
│ ├── secondary-options.js
│ └── tertiary-options.js
├── index.js
├── scss
│ ├── components
│ │ ├── _copy.scss
│ │ ├── _footer.scss
│ │ ├── _nav.scss
│ │ └── _toggle.scss
│ ├── core
│ │ ├── _fonts.scss
│ │ ├── _mixins.scss
│ │ ├── _reboot.scss
│ │ └── _variables.scss
│ ├── main.css
│ ├── main.scss
│ ├── pages
│ │ └── _home.scss
│ └── utilities
│ │ ├── _overrides.scss
│ │ ├── _text.scss
│ │ └── _utils.scss
└── serviceWorker.js
└── yarn.lock
/.dockerignore:
--------------------------------------------------------------------------------
1 | build
2 | node_modules
3 | coverage
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_NODE_PATH=src/
2 | NODE_PATH=src/
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": ["eslint:recommended", "plugin:react/recommended", "airbnb-base"],
4 | "settings": {
5 | "react": {
6 | "pragma": "React",
7 | "version": "16.6.0"
8 | }
9 | },
10 | "parserOptions": {
11 | "ecmaVersion": 9,
12 | "sourceType": "module",
13 | "ecmaFeatures": {
14 | "jsx": true
15 | }
16 | },
17 | "env": {
18 | "browser": true,
19 | "node": true,
20 | "es6": true
21 | },
22 | "rules": {
23 | "comma-dangle": 0,
24 | "global-require": "off",
25 | "prefer-spread": "off",
26 | "no-console": "off",
27 | "no-restricted-syntax": "off",
28 | "no-param-reassign": "off",
29 | "no-plusplus": "off",
30 | "react/prop-types": ["error", { "ignore": ["navigation"] }],
31 | "import/prefer-default-export": "off",
32 | "import/no-extraneous-dependencies": "off",
33 | "no-underscore-dangle": "off",
34 | "no-use-before-define": "off",
35 | "class-methods-use-this": "off",
36 | "import/no-cycle": "off",
37 | "no-nested-ternary": "off",
38 | "consistent-return": "off",
39 | "react/jsx-filename-extension": "off",
40 | "guard-for-in": "off",
41 | "import/no-unresolved": "off",
42 | "no-return-assign": "off"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 | package-lock.json
23 |
24 | .history/
25 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:alpine as builder
2 | ENV NODE_ENV=development \
3 | PORT=3000 \
4 | SHELL=/bin/bash
5 | RUN apk update && apk add --no-cache make git gnupg bash
6 |
7 | # Create app directory
8 | WORKDIR /usr/app
9 |
10 | # Install app dependencies
11 | COPY . ./
12 | RUN npm set progress=false && npm install
13 | VOLUME /usr/app
14 | EXPOSE $PORT
15 | CMD ["npm", "run", "start"]
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Summitech Computing Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GitExplorer
2 | Table of Contents
3 |
4 | [Intro](https://github.com/summitech/gitexplorer/blob/master/README.md#intro)
5 |
6 | [Tech Stack](https://github.com/summitech/gitexplorer/blob/master/README.md#tech-stack)
7 |
8 | [Installation](https://github.com/summitech/gitexplorer/blob/master/README.md#installation)
9 |
10 | [Makers](https://github.com/summitech/gitexplorer/blob/master/README.md#makers)
11 |
12 | [Contribute](https://github.com/summitech/gitexplorer/blob/master/README.md#contribute)
13 |
14 | [Donate](https://github.com/summitech/gitexplorer/blob/master/README.md#donate)
15 |
16 | [RoadMap](https://github.com/summitech/gitexplorer/blob/master/README.md#roadmap)
17 |
18 | ### Intro
19 | Last year, we came across [Sarah Drasner's array explorer](https://github.com/sdras/array-explorer). It is a really cool resource for anyone to easily figure out the best JS array method to use. We loved it and decided to build something similar for Git.
20 |
21 | Website: [Click to find the right git commands without digging through the web.](https://gitexplorer.com)
22 |
23 | Explore and Enjoy!
24 |
25 | You can reach us on [the official git explorer twitter handle](https://twitter.com/gitexplorer) or on [Summitech's twitter handle](https://twitter.com/summitechng).
26 |
27 |
28 | ### Tech Stack
29 |
30 | - React
31 | - Netlify
32 | - Our first hosting platform was [Surge](https://surge.sh). Super easy to set up and very reliable :+1:. 100% recommend!
33 |
34 |
35 | ### Installation
36 | ```
37 | yarn (Install all dependencies)
38 |
39 | yarn start
40 | ```
41 |
42 | To try GitExplorer in a docker container, run this:
43 | ```
44 | docker-compose up
45 | ```
46 |
47 | ### Makers
48 | Awesome devs and designer at [Summitech](https://summitech.ng)
49 |
50 | ### Contribute
51 | Thank you for contributing to GitExplorer!
52 |
53 | Please follow the below instructions to send a Pull Request (Search the website to make sure that this command doesn't already exist).
54 |
55 | The data folder (inside the src directory) is where you will be operating from. The three files you should be concerned with are the `primary-options.js`, `secondary-options.js` and `tertiary-options.js` files.
56 |
57 | These three files are responsible for the options a user can pick.
58 |
59 | `primary-options.js` contains an array of objects responsible for the options of the first select box.
60 | `secondary-options.js` contains an object. This object houses an arrays of objects (a mouthful :smile:), this is responsible for the second set of options a user sees when they select a primary option.
61 | `tertiary-option.js` file is responsible for cases where there needs to be a third & final select box.
62 |
63 | ###### Steps to add a new command
64 | 0. Please ensure you are not on the master branch. Checkout to a new branch entirely.
65 | 1. Add an object to the array in the `primary-options.js` file. Sample Format:
66 | ```
67 | { value: 'show', label: 'show/view' }
68 | ```
69 | 2. Add an array to the `secondary-options` file. Sample Format:
70 | ```
71 | show: [
72 | {
73 | value: 'repo-status',
74 | label: 'status of project including staged, unstaged and untracked files',
75 | usage: 'git status'
76 | nb: 'To know about this command, "run git status --help"'
77 | },
78 | {
79 | value: 'logs',
80 | label: 'commit logs/history'
81 | },
82 | ```
83 | The `nb` is optional. It is responsible for what the user sees in the notes section.
84 |
85 | `\n` is used to insert newline.
86 |
87 | 3. To add tertiary options, remove the `usage` and `nb` key/value pair for that command in the `secondary-options.js` file e.g..
88 |
89 | ```
90 | show: [
91 | {
92 | value: 'logs',
93 | label: 'commit logs/history'
94 | },
95 | ```
96 |
97 | then supply `tertiary-options.js` file the necessary data e.g.
98 | ```
99 | logs: [
100 | {
101 | value: 'all',
102 | label: 'all',
103 | usage: 'git log',
104 | nb: 'Type q in the terminal to exit the logs'
105 | },
106 | {
107 | value: 'last-n-commit',
108 | label: 'for last xxx number of commits',
109 | usage: 'git log -n',
110 | nb: 'Replace n with number of commits e.g. git log -2'
111 | },
112 | {
113 | value: 'particular-period',
114 | label: 'since a particular period',
115 | usage: 'git log --since=period',
116 | nb: 'Replace period with intended timeframe e.g git log --since=3days. You can use dates like 2018-12-31.\n\n Similar flags are --until, --before, --after'
117 | }
118 | ]
119 | ```
120 | 4. Once you are done, add, commit, push and create a PR to Master.
121 |
122 | ### Donate
123 |
124 | You can also contribute to the continued success of the project via donation. Please click this [link](https://rave.flutterwave.com/donate/bavfmdlomzs2).
125 |
126 | ### RoadMap
127 |
128 | - [x] Enforce HTTPs & offline capabilities
129 | - [x] Open source
130 | - [ ] PWA
131 | - [ ] Shareable commands
132 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.2"
2 | services:
3 | gitexplorer:
4 | restart: always
5 | build:
6 | context: ./
7 | cache_from:
8 | - node:alpine
9 | container_name: gitexplorer
10 | hostname: gitexplorer
11 | network_mode: bridge
12 | volumes:
13 | - ./:/usr/app
14 | ports:
15 | - 3000:3000
16 | environment:
17 | - SHELL=/bin/bash
18 | - NODE_ENV=development
19 | - PORT=3000
20 | command:
21 | sh -c 'npm i && npm run start'
22 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "src"
4 | },
5 | "include": ["src"]
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gitexplorer",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "classnames": "^2.2.6",
7 | "node-sass-chokidar": "^1.4.0",
8 | "npm-run-all": "^4.1.5",
9 | "prop-types": "^15.7.2",
10 | "react": "^16.12.0",
11 | "react-device-detect": "^1.11.4",
12 | "react-dom": "^16.12.0",
13 | "react-scripts": "3.4.0",
14 | "react-select": "^2.1.1",
15 | "react-typist": "^2.0.5"
16 | },
17 | "scripts": {
18 | "build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
19 | "watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive",
20 | "start-js": "react-scripts start",
21 | "start": "npm-run-all -p watch-css start-js",
22 | "build": "react-scripts build && cp -r src/assets/images/ build/images",
23 | "test": "react-scripts test --env=jsdom",
24 | "eject": "react-scripts eject",
25 | "lint:check": "eslint . --ext=js,jsx; exit 0",
26 | "lint:fix": "eslint . --ext=js,jsx --fix; exit 0",
27 | "install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf yarn.lock && npm install && npm start"
28 | },
29 | "eslintConfig": {
30 | "extends": "react-app"
31 | },
32 | "browserslist": [
33 | ">0.2%",
34 | "not dead",
35 | "not ie <= 11",
36 | "not op_mini all"
37 | ],
38 | "devDependencies": {
39 | "eslint-config-airbnb": "^17.1.0",
40 | "eslint-config-airbnb-base": "^13.1.0",
41 | "eslint-plugin-react": "^7.11.1"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
23 |
27 |
28 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
59 |
60 | Git Explorer
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Git Explorer",
3 | "name": "Git Explorer",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Footer, Nav } from 'components';
3 | import Typist from 'react-typist';
4 | import { isMobile } from 'react-device-detect';
5 | import { optionsFirst, optionsSecond, optionsThird } from 'data';
6 | import Select from 'react-select';
7 | import clipboard from 'assets/images/clipboard.svg';
8 | import classnames from 'classnames';
9 |
10 | class App extends Component {
11 | constructor(props) {
12 | super(props);
13 | this.state = {
14 | dark: JSON.parse(localStorage.getItem('dark')) || false,
15 | fastType: JSON.parse(localStorage.getItem('fastType')) || false,
16 | firstOption: null,
17 | showSecond: false,
18 | secondOption: null,
19 | showThird: false,
20 | thirdOption: null,
21 | nb: '',
22 | usage: '',
23 | copied: false
24 | };
25 | }
26 |
27 | handleToggle = (evt) => {
28 | const { id } = evt.target;
29 |
30 | this.setState(
31 | prevState => ({ [id]: !prevState[id] }),
32 | () => {
33 | localStorage.setItem(id, this.state[id]);
34 | }
35 | );
36 | };
37 |
38 | onFirstChange = (selectedOption) => {
39 | if (this.state.secondOption) {
40 | this.setState({
41 | firstOption: selectedOption,
42 | showSecond: true,
43 | secondOption: null,
44 | showThird: false,
45 | nb: '',
46 | usage: ''
47 | });
48 | } else if (optionsSecond[selectedOption.value].length === 1) {
49 | this.setState({ firstOption: selectedOption, showSecond: true });
50 | this.onSecondChange(optionsSecond[selectedOption.value][0]);
51 | } else {
52 | this.setState({ firstOption: selectedOption, showSecond: true });
53 | }
54 | };
55 |
56 | onSecondChange = (selectedOption) => {
57 | if (selectedOption.usage) {
58 | this.setState({ nb: '', usage: '' }, () => {
59 | this.setState({
60 | secondOption: selectedOption,
61 | showThird: false,
62 | nb: selectedOption.nb,
63 | usage: selectedOption.usage,
64 | thirdOption: null
65 | });
66 | });
67 | } else if (optionsThird[selectedOption.value].length === 1) {
68 | this.setState({
69 | secondOption: selectedOption,
70 | showThird: true,
71 | thirdOption: null,
72 | nb: '',
73 | usage: ''
74 | });
75 | this.onThirdChange(optionsThird[selectedOption.value][0]);
76 | } else {
77 | this.setState({
78 | secondOption: selectedOption,
79 | showThird: true,
80 | thirdOption: null,
81 | nb: '',
82 | usage: ''
83 | });
84 | }
85 | };
86 |
87 | onThirdChange = (selectedOption) => {
88 | this.setState({ nb: '', usage: '' }, () => {
89 | this.setState({
90 | thirdOption: selectedOption,
91 | nb: selectedOption.nb,
92 | usage: selectedOption.usage
93 | });
94 | });
95 | };
96 |
97 | onCopy = () => {
98 | this.setState({ copied: true }, () => {
99 | if (this.timeout) {
100 | clearInterval(this.timeout);
101 | }
102 | this.timeout = setTimeout(() => {
103 | this.setState({ copied: false });
104 | }, 1000);
105 | });
106 | };
107 |
108 | copyUsage = () => {
109 | const el = document.createElement('textarea');
110 | el.value = this.state.usage;
111 | el.setAttribute('readonly', '');
112 | el.style.position = 'absolute';
113 | el.style.left = '-9999px';
114 | document.body.appendChild(el);
115 | const selected = document.getSelection().rangeCount > 0
116 | ? document.getSelection().getRangeAt(0)
117 | : false;
118 | el.select();
119 | document.execCommand('copy');
120 | document.body.removeChild(el);
121 | this.onCopy();
122 |
123 | if (selected) {
124 | document.getSelection().removeAllRanges();
125 | document.getSelection().addRange(selected);
126 | }
127 | };
128 |
129 | render() {
130 | const {
131 | dark,
132 | firstOption,
133 | secondOption,
134 | thirdOption,
135 | showSecond,
136 | showThird,
137 | fastType,
138 | nb,
139 | usage,
140 | copied
141 | } = this.state;
142 | const avgTypingDelay = fastType ? 0 : 50;
143 |
144 | return (
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 | Git Command Explorer
153 |
154 |
155 | Find the right commands you need without digging through the web.
156 |
157 |
158 |
159 |
I want to:
160 |
161 |
170 |
171 | {showSecond ? (
172 |
181 | ) : null}
182 |
183 | {showThird ? (
184 |
193 | ) : null}
194 |
195 |
196 |
197 |
200 |
Usage
201 |
202 |
203 | {usage.length ? (
204 |
205 | {usage}
206 |
207 | ) : (
208 |
209 | )}
210 |
211 | {usage.length ? (
212 |
213 |
214 | command copied
215 |
216 |

222 |
223 | ) : null}
224 |
225 |
226 | {nb ? (
227 |
228 |
Note
229 |
230 |
231 |
232 | {nb}
233 |
234 |
235 |
236 |
237 | ) : null}
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 | );
246 | }
247 | }
248 |
249 | export default App;
250 |
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans/OpenSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/assets/fonts/OpenSans/OpenSans-Bold.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans/OpenSans-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/assets/fonts/OpenSans/OpenSans-ExtraBold.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans/OpenSans-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/assets/fonts/OpenSans/OpenSans-Light.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans/OpenSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/assets/fonts/OpenSans/OpenSans-Regular.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/OpenSans/OpenSans-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/assets/fonts/OpenSans/OpenSans-SemiBold.ttf
--------------------------------------------------------------------------------
/src/assets/images/clipboard.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
50 |
--------------------------------------------------------------------------------
/src/assets/images/gitcommand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/assets/images/gitcommand.png
--------------------------------------------------------------------------------
/src/assets/images/github-green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import github from 'assets/images/github.svg';
4 | import githubGreen from 'assets/images/github-green.svg';
5 |
6 | const Footer = props => (
7 |
40 | );
41 |
42 | Footer.propTypes = {
43 | dark: PropTypes.bool
44 | };
45 |
46 | export { Footer };
47 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | export * from './footer';
2 | export * from './nav';
3 |
--------------------------------------------------------------------------------
/src/components/nav.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import Toggle from './toggle';
4 |
5 | const Nav = ({ fastType, mode, onToggle }) => (
6 |
22 | );
23 |
24 | Nav.propTypes = {
25 | fastType: PropTypes.bool,
26 | mode: PropTypes.bool,
27 | onToggle: PropTypes.func,
28 | };
29 |
30 | export { Nav };
31 |
--------------------------------------------------------------------------------
/src/components/toggle.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const Toggle = ({
5 | checked, leftLabel, name, onChange, rightLabel
6 | }) => (
7 |
8 |
{leftLabel}
9 |
10 |
15 |
16 |
{rightLabel}
17 |
18 | );
19 |
20 | Toggle.propTypes = {
21 | checked: PropTypes.bool,
22 | leftLabel: PropTypes.string,
23 | name: PropTypes.string.isRequired,
24 | onChange: PropTypes.func,
25 | rightLabel: PropTypes.string
26 | };
27 |
28 | export default Toggle;
29 |
--------------------------------------------------------------------------------
/src/data/index.js:
--------------------------------------------------------------------------------
1 | export { primaryOptions as optionsFirst } from './primary-options';
2 | export { secondaryOptions as optionsSecond } from './secondary-options';
3 | export { tertiaryOptions as optionsThird } from './tertiary-options';
4 |
--------------------------------------------------------------------------------
/src/data/primary-options.js:
--------------------------------------------------------------------------------
1 | const options = [
2 | { value: 'add', label: 'add' },
3 | { value: 'commit', label: 'commit' },
4 | { value: 'revert', label: 'revert/reset' },
5 | { value: 'initialize', label: 'initialize' },
6 | { value: 'modify', label: 'modify' },
7 | { value: 'show', label: 'show/view' },
8 | { value: 'delete', label: 'delete/remove' },
9 | { value: 'compareCommits', label: 'compare two commits' },
10 | { value: 'configure', label: 'configure' },
11 | { value: 'clone', label: 'clone' },
12 | { value: 'ignore', label: 'ignore' },
13 | { value: 'rename', label: 'rename' },
14 | { value: 'merge', label: 'merge' },
15 | { value: 'squash', label: 'squash' },
16 | { value: 'stash', label: 'stash' },
17 | { value: 'debug', label: 'debug' },
18 | { value: 'recover', label: 'recover' },
19 | { value: 'synchronize', label: 'synchronize' },
20 | { value: 'rebase', label: 'rebase' },
21 | { value: 'cherrypick', label: 'cherry-pick' },
22 | ];
23 |
24 | export const primaryOptions = options.sort((x, y) => {
25 | if (x.value < y.value) {
26 | return -1;
27 | }
28 | if (x.value > y.value) {
29 | return 1;
30 | }
31 | return 0;
32 | });
33 |
--------------------------------------------------------------------------------
/src/data/secondary-options.js:
--------------------------------------------------------------------------------
1 | export const secondaryOptions = {
2 | commit: [
3 | {
4 | value: 'local-changes',
5 | label: 'commit all local changes in tracked files',
6 | usage: 'git commit -a'
7 | },
8 | {
9 | value: 'staged-changes',
10 | label: 'commit all staged changes',
11 | usage: 'git commit -m ',
12 | nb: 'Replace with your commit message.'
13 | }
14 | ],
15 |
16 | configure: [
17 | {
18 | value: 'email-name',
19 | label: 'name and email address',
20 | usage:
21 | 'git config --global user.name "username" \n\ngit config --global user.email "email address"',
22 | nb:
23 | 'Your username and email address should be the same as the one used with your git hosting provider i.e. github, bitbucket, gitlab etc'
24 | },
25 | {
26 | value: 'editor',
27 | label: 'default editor',
28 | usage: 'git config --global core.editor "vim"',
29 | nb: 'Change default editor to vim.'
30 | },
31 | {
32 | value: 'diff-tool',
33 | label: 'external diff tool',
34 | usage: 'git config --global diff.external "meld"',
35 | nb: 'Set external diff tool to meld.'
36 | },
37 | {
38 | value: 'merge-tool',
39 | label: 'default merge tool',
40 | usage: 'git config --global merge.tool "meld"',
41 | nb: 'Set default merge tool to meld.'
42 | },
43 | {
44 | value: 'color',
45 | label: 'color',
46 | usage: 'git config --global color.ui auto',
47 | nb: 'Enables helpful colorization of command line output'
48 | },
49 | {
50 | value: 'signingkey',
51 | label: 'add the GPG key',
52 | usage: 'git config --global user.signingkey ',
53 | nb:
54 | 'Git is cryptographically secure, but it’s not foolproof. If you’re taking work from others on the internet and want to verify that commits are actually from a trusted source, Git has a few ways to sign and verify work using GPG.'
55 | }
56 | ],
57 |
58 | revert: [
59 | {
60 | value: 'specific-commit',
61 | label: 'a specific commit',
62 | usage: 'git revert ',
63 | nb: 'Use git log to see the hash of each commit'
64 | },
65 | {
66 | value: 'specific-file',
67 | label: 'a specific file',
68 | usage: 'git checkout / ',
69 | },
70 | {
71 | value: 'to-last-commit',
72 | label: 'to last commit',
73 | usage: 'git reset --hard'
74 | },
75 | {
76 | value: 'to-last-commit-from-remote',
77 | label: 'to last commit on remote branch',
78 | usage: 'git reset --hard /'
79 | }
80 | ],
81 |
82 | initialize: [
83 | {
84 | value: 'new-repo',
85 | label: 'a new repository',
86 | nb: 'Make sure you are in the right directory',
87 | usage: 'git init'
88 | }
89 | ],
90 |
91 | modify: [
92 | {
93 | value: 'commit-message',
94 | label: 'my last/latest commit message',
95 | usage: 'git commit --amend'
96 | },
97 | {
98 | value: 'commit',
99 | label: 'my last commit but leave the commit message as is',
100 | usage: 'git add . \ngit commit --amend --no-edit'
101 | },
102 | {
103 | value: 'remoteUrl',
104 | label: "repo's remote url",
105 | usage: 'git remote set-url ',
106 | nb: ' is your remote name e.g origin'
107 | }
108 | ],
109 |
110 | show: [
111 | {
112 | value: 'repo-status',
113 | label: 'status of project including staged, unstaged and untracked files',
114 | usage: 'git status'
115 | },
116 | {
117 | value: 'logs',
118 | label: 'commit logs/history'
119 | },
120 | {
121 | value: 'uncommittedChanges',
122 | label: 'uncommitted changes',
123 | usage: 'git diff'
124 | },
125 | {
126 | value: 'committedChanges',
127 | label: 'committed/staged changes',
128 | usage: 'git diff --staged'
129 | },
130 | {
131 | value: 'remoteUrl',
132 | label: "repo's remote url",
133 | usage: 'git remote -v'
134 | },
135 | {
136 | value: 'stash',
137 | label: 'stash',
138 | usage: 'git stash list'
139 | },
140 | {
141 | value: 'branch',
142 | label: 'branches',
143 | usage: 'git branch',
144 | nb: 'The active branch is prefixed with *'
145 | },
146 | {
147 | value: 'tags',
148 | label: 'tags',
149 | usage: 'git tag'
150 | }
151 | ],
152 |
153 | delete: [
154 | {
155 | value: 'branch',
156 | label: 'a branch',
157 | usage: 'git branch -D '
158 | },
159 | {
160 | value: 'delete-multiple-branches',
161 | label: 'multiple branches',
162 | },
163 | {
164 | value: 'tag',
165 | label: 'a tag',
166 | usage: 'git tag -d v'
167 | },
168 | {
169 | value: 'remote',
170 | label: 'remote',
171 | usage: 'git remote rm '
172 | },
173 | {
174 | value: 'untracked-files',
175 | label: 'untracked files',
176 | usage: 'git clean -',
177 | nb:
178 | 'replace - with:\n -i for interactive command\n -n to preview what will be removed\n -f to remove forcefully\n -d to remove directories\n -X to remove ignored files\n -x to remove ignored and non-ignored files'
179 | },
180 | {
181 | value: 'files-from-index',
182 | label: 'files from index',
183 | usage: 'git rm --cached ',
184 | nb:
185 | 'Use this option to unstage and remove paths only from the index. Working tree files, whether modified or not, will be left alone.'
186 | },
187 | {
188 | value: 'local-branches-not-on-remote',
189 | label: "local branches that don't exist at remote",
190 | usage: 'git remote prune ',
191 | nb:
192 | 'Use the --dry-run option to report what branches will be pruned, but do not actually prune them'
193 | },
194 | {
195 | value: 'files-from-old-commit',
196 | label: 'files from old commits',
197 | usage:
198 | "git filter-branch --index-filter \n'git rm --cached --ignore-unmatch path/to/mylarge_file' \n--tag-name-filter cat -- --all\n\nfilter-branch keeps backups too, so the size of the repo won't decrease immediately unless you expire the reflogs and garbage collect:\n\nrm -Rf .git/refs/original # careful\ngit gc --aggressive --prune=now # danger",
199 | nb:
200 | "Like the rebasing option described before, filter-branch is rewriting operation. If you have published history, you'll have to --force push the new refs."
201 | }
202 | ],
203 |
204 | compareCommits: [
205 | {
206 | value: 'terminal',
207 | label: 'and output result in the terminal',
208 | usage: 'git diff ',
209 | nb: 'sha1 and sha2 are the sha hash of the commits you want to compare.'
210 | },
211 | {
212 | value: 'file',
213 | label: 'and output result to a file',
214 | usage: 'git diff > diff.txt',
215 | nb:
216 | 'sha1 and sha2 are the sha of the commits you want to compare. \n\ndiff.txt is the file you want to store the contents of the diff'
217 | }
218 | ],
219 |
220 | clone: [
221 | {
222 | value: 'clone-repo-into-a-new-dir',
223 | label: 'existing repo into a new directory',
224 | usage: 'git clone ',
225 | nb:
226 | 'The repo is cloned into the specified directory\n\nReplace "directory" with the directory you want'
227 | },
228 | {
229 | value: 'clone-repo-into-a-current-dir',
230 | label: 'existing repo into the current directory',
231 | usage: 'git clone .',
232 | nb:
233 | 'The repo is cloned into the current directory\n\nThe current directory is represented with a "." (period)'
234 | },
235 | {
236 | value: 'clone-repo-with-submodule-into-a-current-dir',
237 | label: 'existing repo along with submodules into the current directory',
238 | usage: 'git clone --recurse-submodules .',
239 | nb: 'If git version is under 2.13, use --recursive option instead.'
240 | },
241 | {
242 | value: 'clone-submodule-after',
243 | label: 'submodules after cloning existing repo',
244 | usage: 'git submodule update --init --recursive'
245 | }
246 | ],
247 |
248 | ignore: [
249 | {
250 | value: 'ignore-files-in-a-dir',
251 | label: 'all files in a directory',
252 | usage: '/*',
253 | nb:
254 | 'This must be added to .gitignore file\n\nReplace "dir name" with name of directory whose files you want git to ignore'
255 | },
256 | {
257 | value: 'ignore-all-files-of-a-specific-type',
258 | label: 'all files of a specific type',
259 | usage: '*.',
260 | nb:
261 | 'This must be added to .gitignore file\n\nReplace "filename extension" with the extension of the files you want git to ignore\n\nFor example *.py tells git to ignore all python files in the repository'
262 | }
263 | ],
264 |
265 | help: [
266 | {
267 | value: 'command-help',
268 | label: 'about a command',
269 | usage: 'append --help to the command',
270 | nb: 'e.g. git merge --help\n\nType q to quite terminal'
271 | }
272 | ],
273 |
274 | add: [
275 | {
276 | value: 'new-changes',
277 | label: 'new changes',
278 | usage: 'git add ',
279 | nb:
280 | 'To add all the files in the current directory, use "git add ."\n\nTo add a directory use "git add "'
281 | },
282 | {
283 | value: 'add-new-branch',
284 | label: 'a new branch'
285 | },
286 | {
287 | value: 'add-repo',
288 | label: 'new remote repo',
289 | usage: 'git remote add '
290 | },
291 | {
292 | value: 'add-alias',
293 | label: 'alias',
294 | usage: 'git config --global alias. ',
295 | nb:
296 | 'e.g. git config --global alias.st status. Typing git st in the terminal now does the same thing as git status'
297 | },
298 | {
299 | value: 'add-annotated-tag',
300 | label: 'annotated tag',
301 | usage: 'git tag -a v1.4 -m "my version 1.4"\n\ngit push --tags'
302 | },
303 | {
304 | value: 'add-annotated-tag-for-old-commit',
305 | label: 'annotated tag for old commit',
306 | usage: "git tag -a v1.2 -m 'version 1.2' \n\ngit push --tags"
307 | }
308 | ],
309 |
310 | push: [
311 | {
312 | value: 'new-remote-branch',
313 | label: 'non-existent remote branch',
314 | usage: 'git push -u origin '
315 | }
316 | ],
317 |
318 | rename: [
319 | {
320 | value: 'branch',
321 | label: 'branch'
322 | },
323 | {
324 | value: 'file',
325 | label: 'file',
326 | usage: 'git mv file_from file_to'
327 | },
328 | {
329 | value: 'remoteUrl',
330 | label: 'remote',
331 | usage: 'git remote rename '
332 | }
333 | ],
334 |
335 | merge: [
336 | {
337 | value: 'branch',
338 | label: 'another branch to current branch',
339 | usage: 'git merge '
340 | },
341 | {
342 | value: 'single-file',
343 | label: 'merge a single file from one branch to another.',
344 | usage: 'git checkout --patch'
345 | }
346 | ],
347 |
348 | squash: [
349 | {
350 | value: 'pr',
351 | label: 'commits in pull request into single commit',
352 | usage: 'git rebase -i ',
353 | nb:
354 | 'Make sure that latest commits are fetched from upstream.\n\nFor example (assuming you have a remote named upstream):\n\ngit fetch upstream\ngit rebase -i upstream/master\n\nChange "pick" to "squash" for the commits you wish to squash and save.\n\ngit push origin --force-with-lease'
355 | },
356 | {
357 | value: 'commits',
358 | label: 'last n number of commit into one',
359 | usage:
360 | 'git reset --soft HEAD~N\ngit add .\ngit commit -m ',
361 | nb:
362 | "Replace N with the number of commits you want to squash and with your commit message. You can use the command 'git log' to view your commit history"
363 | }
364 | ],
365 |
366 | debug: [
367 | {
368 | value: 'bisect',
369 | label: 'binary search',
370 | usage:
371 | 'git bisect start\ngit bisect bad # Current version is bad\ngit bisect good v2.13 # v6.12 is known to be good',
372 | nb:
373 | 'Once you have specified at least one bad and one good commit, git bisect selects a commit in the middle of that range of history, checks it out, and outputs something similar to the following:\nBisecting: 675 revisions left to test after this (roughly 10 steps)\nYou should now compile the checked-out version and test it. If that version works correctly, type\n\ngit bisect good\n\nIf that version is broken, type\n\ngit bisect bad\n\nThen git bisect will respond with something like\n\nBisecting: 337 revisions left to test after this (roughly 9 steps)\n\nKeep repeating the process: compile the tree, test it, and depending on whether it is good or bad run git bisect good or git bisect bad to ask for the next commit that needs testing.\nEventually there will be no more revisions left to inspect, and the command will print out a description of the first bad commit. The reference refs/bisect/bad will be left pointing at that commit.\nAfter a bisect session, to clean up the bisection state and return to the original HEAD, issue the following command:\n\ngit bisect reset'
374 | },
375 | {
376 | value: 'blame',
377 | label: 'who modified each lines',
378 | usage: 'git blame -L , ',
379 | nb: 'The -L option will restrict the output to the requested line range\n'
380 | },
381 | {
382 | value: 'grep',
383 | label: 'search in files',
384 | usage: 'git grep -n ',
385 | nb:
386 | 'Print lines matching a pattern.\nOption -n to display the numbering of lines in which there are matches'
387 | }
388 | ],
389 |
390 | recover: [
391 | {
392 | value: 'dropped-commit',
393 | label: 'show hashes dangling commits after hard reset to previous commit',
394 | usage: 'git reflog',
395 | nb:
396 | 'alternative: git log -g. For recovery use\ngit checkout -b '
397 | },
398 | {
399 | value: 'deleted-branch',
400 | label: 'show hashes removed branch or other git objects',
401 | usage: 'git fsck --full',
402 | nb:
403 | 'show hashes all dangling git objects. For recovery use\ngit checkout -b '
404 | }
405 | ],
406 |
407 | rebase: [
408 | {
409 | value: 'origin-branch',
410 | label: 'an origin branch into my working branch',
411 | usage: 'git pull --rebase origin ',
412 | nb:
413 | 'Rebase an origin branch into working branch. Replace with the branch you are pulling'
414 | },
415 | {
416 | value: 'local-branch',
417 | label: 'a local branch into my working branch',
418 | usage: 'git rebase ',
419 | nb:
420 | 'Rebase another local branch into working branch. Replace with the branch you are pulling'
421 | },
422 | {
423 | value: 'skip',
424 | label: 'and skip a commit',
425 | usage: 'git rebase --skip',
426 | nb:
427 | 'During rebase, git might not be able to automatically apply commits due to conflicts. You can use this command to discard of your own changes in the current commit and apply the changes from an incoming branch'
428 | },
429 | {
430 | value: 'continue',
431 | label: 'and continue after resolving conflicts',
432 | usage: 'git rebase --continue',
433 | nb:
434 | 'During rebase, git might not be able to automatically apply commits due to conflicts. You can resolve this conflicts manually and use this command to continue your rebase operation'
435 | }
436 | ],
437 |
438 | synchronize: [
439 | {
440 | value: 'branch-from-fork',
441 | label: 'a branch in a fork',
442 | usage:
443 | 'git fetch \n\ngit checkout \n\ngit merge /',
444 | nb: 'You need to add a remote repo for your fork first.'
445 | }
446 | ],
447 | stash: [
448 | {
449 | value: 'save-stash',
450 | label: '(un)tracked files',
451 | usage: 'git stash',
452 | nb: 'To stash with a customized message use git stash save \n\nTo stash untracked files git stash save -u'
453 | },
454 | {
455 | value: 'list-stash',
456 | label: 'view list of stashed changes',
457 | usage: 'git stash list'
458 | },
459 | {
460 | value: 'apply-stash',
461 | label: 'apply'
462 | },
463 | {
464 | value: 'show',
465 | label: 'view the contents of a stash',
466 | usage: 'git stash show -p ',
467 | nb: 'You can leave out the stash id if you want the contents of the latest stash'
468 | },
469 | {
470 | value: 'delete-stash',
471 | label: 'delete'
472 | },
473 | {
474 | value: 'create-branch',
475 | label: 'create a new branch and apply stash',
476 | usage: 'git stash branch '
477 | }
478 | ],
479 |
480 | cherrypick: [
481 | {
482 | value: 'origin-branch',
483 | label: 'an commit from origin branch into my working branch',
484 | usage: 'git cherry-pick ',
485 | nb:
486 | 'Applying one or more commit from one branch into your working branch. '
487 | },
488 | ],
489 | };
490 |
--------------------------------------------------------------------------------
/src/data/tertiary-options.js:
--------------------------------------------------------------------------------
1 | export const tertiaryOptions = {
2 | logs: [
3 | {
4 | value: 'all',
5 | label: 'all',
6 | usage: 'git log',
7 | nb: 'Type q in the terminal to exit the logs'
8 | },
9 | {
10 | value: 'last-n-commit',
11 | label: 'for last xxx number of commits',
12 | usage: 'git log -n',
13 | nb: 'Replace n with number of commits e.g. git log -2'
14 | },
15 | {
16 | value: 'particular-period',
17 | label: 'since a particular period',
18 | usage: 'git log --since=period',
19 | nb: 'Replace period with intended timeframe e.g git log --since=3days. You can use dates like 2018-12-31.\n\n Similar flags are --until, --before, --after'
20 | },
21 | {
22 | value: 'commit-on-oneline',
23 | label: 'with each commit on one line',
24 | usage: 'git log --oneline'
25 | },
26 | {
27 | value: 'patches-introduced',
28 | label: 'with the patches introduced in each commit',
29 | usage : 'git log -p'
30 | }
31 | ],
32 | branch: [
33 | {
34 | value: 'in',
35 | label: 'while working in the branch',
36 | usage: 'git branch -m '
37 | },
38 | {
39 | value: 'outside',
40 | label: 'from outside the branch',
41 | usage: 'git branch -m '
42 | }
43 | ],
44 | 'add-new-branch': [
45 | {
46 | value: 'no-checkout',
47 | label: 'but remain in the current branch I am working from',
48 | usage: 'git branch '
49 | },
50 | {
51 | value: 'checkout',
52 | label: 'and switch to the new branch',
53 | usage: 'git checkout -b '
54 | },
55 | {
56 | value: 'checkout-remote',
57 | label: 'from another branch',
58 | usage: 'git checkout -b '
59 | }
60 | ],
61 | 'apply-stash': [
62 | {
63 | value: 'latest',
64 | label: 'latest stash',
65 | usage: 'git stash apply'
66 | },
67 | {
68 | value: 'specific',
69 | label: 'a specific stash',
70 | usage: 'git stash apply ',
71 | nb: 'The stash id can be gotten when you run git stash list. It\'s usually in this format: stash@{index} e.g. stash@{0}'
72 | },
73 | {
74 | value: 'pop',
75 | label: 'and delete stash',
76 | usage: 'git stash pop ',
77 | nb: 'Stash id optional. Add it if you want to apply and delete a specific stash otherwise leave to pop the latest stash'
78 | }
79 | ],
80 | 'delete-stash': [
81 | {
82 | value: 'all',
83 | label: 'all stashed changes',
84 | usage: 'git stash clear'
85 | },
86 | {
87 | value: 'specific',
88 | label: 'specific stash',
89 | usage: 'git stash drop '
90 | },
91 | ],
92 | 'delete-multiple-branches': [
93 | {
94 | value: 'name',
95 | label: 'by name',
96 | usage: 'git branch -D '
97 | },
98 | {
99 | value: 'pattern',
100 | label: 'by pattern',
101 | usage: 'git branch | grep | xargs git branch -D',
102 | nb: 'e.g. git branch | grep "-" | xargs git branch -D will delete all branches that have \'-\' in their names or git branch | grep -v "master\\|staging" | xargs git branch -D will delete all branches except staging and master.\n\nNB: Always put your regex pattern in quotes'
103 | }
104 | ]
105 | };
106 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from 'App';
4 | import 'scss/main.css';
5 | import * as serviceWorker from 'serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.register();
13 |
--------------------------------------------------------------------------------
/src/scss/components/_copy.scss:
--------------------------------------------------------------------------------
1 | .copy {
2 | position: relative;
3 | display: inline-block;
4 | &__image {
5 | cursor: pointer;
6 | position: relative;
7 | width: 2rem;
8 | }
9 |
10 | &__popover {
11 | background: $color-white;
12 | border-radius: 0.3rem;
13 | bottom: 50%;
14 | color: $color-dark !important;
15 | display: inline-block;
16 | font-size: 1rem;
17 | padding: 0.2rem 0.5rem;
18 | position: absolute;
19 | opacity: 0;
20 | right: 50%;
21 | text-align: center;
22 | text-transform: capitalize;
23 | transform: translateX(50%);
24 | transition: all 0.3s;
25 |
26 | &.show {
27 | opacity: 1;
28 | bottom: 150%;
29 | }
30 |
31 | &::after {
32 | @include triangle('down', 5px, $color-white);
33 | content: '';
34 | display: block;
35 | left: 50%;
36 | position: absolute;
37 | transform: translateX(-50%);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/scss/components/_footer.scss:
--------------------------------------------------------------------------------
1 | .footer {
2 | margin-top: 2rem;
3 |
4 | &__copyright {
5 | display: block;
6 | @include text();
7 | text-align: center;
8 | line-height: 4rem;
9 |
10 | span {
11 | color: crimson;
12 | }
13 |
14 | &:hover {
15 | color: initial;
16 | }
17 |
18 | a {
19 | color: inherit;
20 |
21 | &:hover {
22 | text-decoration: underline;
23 | }
24 | }
25 | }
26 |
27 | .logo {
28 | float: right;
29 |
30 | @include respond('as') {
31 | justify-content: center;
32 | margin-bottom: 1rem;
33 | }
34 |
35 | &--github {
36 | width: 4rem;
37 | height: 4rem;
38 | fill: blue;
39 | }
40 | }
41 |
42 | &__link {
43 | margin-left: 2rem;
44 | position: relative;
45 |
46 | &::before {
47 | content: '';
48 | display: inline-block;
49 | width: 3px;
50 | height: 3px;
51 | border-radius: 100%;
52 | background-color: white;
53 | position: absolute;
54 | top: 50%;
55 | transform: translateY(-50%);
56 | left: -1.2rem;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/scss/components/_nav.scss:
--------------------------------------------------------------------------------
1 | .nav {
2 | align-items: center;
3 | display: flex;
4 | justify-content: space-between;
5 |
6 | @include respond('xs') {
7 | align-items: center;
8 | flex-direction: column;
9 | justify-content: center;
10 | }
11 |
12 | .language {
13 | align-items: center;
14 | display: flex;
15 | margin-right: 4rem;
16 |
17 | @include respond('xs') {
18 | margin-right: 0;
19 | margin-bottom: 2rem;
20 | }
21 |
22 | &__title {
23 | @include text();
24 | }
25 |
26 | &__select {
27 | width: 15rem;
28 | margin-left: 3rem;
29 |
30 | &__control {
31 | border: none;
32 | box-shadow: 1px 2px 2px rgba($color-black, 0.1);
33 | }
34 |
35 | &__indicator-separator {
36 | display: none;
37 | }
38 |
39 | &__single-value {
40 | @include text();
41 | }
42 |
43 | &__menu {
44 | margin: 0;
45 | padding: 0 !important;
46 |
47 | &-list {
48 | padding: 0 !important;
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/scss/components/_toggle.scss:
--------------------------------------------------------------------------------
1 | $width: 45px;
2 | $height: 10px;
3 |
4 | .toggle {
5 | display: flex;
6 | justify-content: flex-start;
7 | align-items: center;
8 | &__option {
9 | @include text();
10 | transition: all 0.3s;
11 | &--left {
12 | margin-right: 1rem;
13 | }
14 | &--right {
15 | margin-left: 1rem;
16 | }
17 | }
18 | @include respond('xs') {
19 | margin-bottom: 2rem;
20 | }
21 | }
22 |
23 | .toggler {
24 | display: inline-block;
25 | margin: (($height * 1.4 - $height) / 2) + 5px;
26 | margin: (($height * 1.5 - $height) / 2);
27 | width: $width;
28 | height: $height;
29 | text-align: center;
30 | position: relative;
31 | input[type='checkbox'] {
32 | display: none;
33 | &:checked ~ .button {
34 | background: $color-white;
35 | left: $width - ($height * 2);
36 | transition: 0.5s;
37 | }
38 | &:checked ~ .switch {
39 | background: darken($color-primary, 1);
40 | transition: 0.5s;
41 | }
42 | }
43 | .switch {
44 | display: block;
45 | width: $width;
46 | height: $height;
47 | background: $color-primary;
48 | border-radius: $height / 2;
49 | position: absolute;
50 | top: 0;
51 | left: 0;
52 | transition: 0.5s;
53 | cursor: pointer;
54 | }
55 | .button {
56 | height: $height * 2;
57 | width: $height * 2;
58 | border-radius: 50%;
59 | background: white;
60 | position: absolute;
61 | top: ($height * 2 - $height) / -2;
62 | left: 0;
63 | box-shadow: 0 $width / 50 $width / 25 rgba(black, 0.4);
64 | transition: 0.5s;
65 | cursor: pointer;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/scss/core/_fonts.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "OpenSans";
3 | font-style: normal;
4 | font-weight: 300;
5 | src: url("../assets/fonts/OpenSans/OpenSans-Light.ttf") format("truetype");
6 | text-rendering: optimizeLegibility;
7 | }
8 |
9 | @font-face {
10 | font-family: "OpenSans";
11 | font-style: normal;
12 | font-weight: normal;
13 | src: url("../assets/fonts/OpenSans/OpenSans-Regular.ttf") format("truetype");
14 | text-rendering: optimizeLegibility;
15 | }
16 |
17 | @font-face {
18 | font-family: "OpenSans";
19 | font-style: normal;
20 | font-weight: 600;
21 | src: url("../assets/fonts/OpenSans/OpenSans-SemiBold.ttf") format("truetype");
22 | text-rendering: optimizeLegibility;
23 | }
24 |
25 | @font-face {
26 | font-family: "OpenSans";
27 | font-style: normal;
28 | font-weight: bold;
29 | src: url("../assets/fonts/OpenSans/OpenSans-Bold.ttf") format("truetype");
30 | text-rendering: optimizeLegibility;
31 | }
32 |
33 | @font-face {
34 | font-family: "OpenSans";
35 | font-style: normal;
36 | font-weight: 800;
37 | src: url("../assets/fonts/OpenSans/OpenSans-ExtraBold.ttf") format("truetype");
38 | text-rendering: optimizeLegibility;
39 | }
40 |
--------------------------------------------------------------------------------
/src/scss/core/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin respond($breakpoint) {
2 | @if ($breakpoint== 'xs') {
3 | @media (max-width: 575px) {
4 | @content;
5 | }
6 | }
7 | @if ($breakpoint== 'sm') {
8 | @media (min-width: 576px) and (max-width: 767px) {
9 | @content;
10 | }
11 | }
12 | @if ($breakpoint== 'as') {
13 | @media (max-width: 768px) {
14 | @content;
15 | }
16 | }
17 | @if ($breakpoint== 'ab') {
18 | @media (min-width: 769px) {
19 | @content;
20 | }
21 | }
22 | @if ($breakpoint== 'am') {
23 | @media (max-width: 991px) {
24 | @content;
25 | }
26 | }
27 | @if ($breakpoint== 'fm') {
28 | @media (min-width: 992px) {
29 | @content;
30 | }
31 | }
32 | @if ($breakpoint== 'md') {
33 | @media (min-width: 768px) and (max-width: 991px) {
34 | @content;
35 | }
36 | }
37 | @if ($breakpoint== 'lg') {
38 | @media (min-width: 992px) and (max-width: 1199px) {
39 | @content;
40 | }
41 | }
42 | @if ($breakpoint== 'md-lg') {
43 | @media (min-width: 768px) and (max-width: 1199px) {
44 | @content;
45 | }
46 | }
47 | @if ($breakpoint== 'xl') {
48 | @media (min-width: 1200px) {
49 | @content;
50 | }
51 | }
52 | }
53 |
54 | @mixin text {
55 | color: $color-text;
56 | font-size: 1.4rem;
57 | letter-spacing: 1px;
58 | margin: 0;
59 | transition: 0.1s color;
60 | }
61 |
62 | @mixin triangle($dir, $size, $color) {
63 | border: $size transparent solid;
64 | @if ($dir== 'top' or $dir== 'up') {
65 | border-bottom-color: $color;
66 | } @else if ($dir== 'right' or $dir== 'after') {
67 | border-left-color: $color;
68 | } @else if ($dir== 'bottom' or $dir== 'down') {
69 | border-top-color: $color;
70 | } @else if ($dir== 'left' or $dir== 'before') {
71 | border-right-color: $color;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/scss/core/_reboot.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.1.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2018 The Bootstrap Authors
4 | * Copyright 2011-2018 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | html {
15 | font-family: sans-serif;
16 | line-height: 1.15;
17 | -webkit-text-size-adjust: 100%;
18 | -ms-text-size-adjust: 100%;
19 | -ms-overflow-style: scrollbar;
20 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
21 | }
22 |
23 | @-ms-viewport {
24 | width: device-width;
25 | }
26 |
27 | article,
28 | aside,
29 | figcaption,
30 | figure,
31 | footer,
32 | header,
33 | hgroup,
34 | main,
35 | nav,
36 | section {
37 | display: block;
38 | }
39 |
40 | body {
41 | margin: 0;
42 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif,
43 | "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
44 | font-size: 1rem;
45 | font-weight: 400;
46 | line-height: 1.5;
47 | color: #212529;
48 | text-align: left;
49 | background-color: #fff;
50 | }
51 |
52 | [tabindex="-1"]:focus {
53 | outline: 0 !important;
54 | }
55 |
56 | hr {
57 | box-sizing: content-box;
58 | height: 0;
59 | overflow: visible;
60 | }
61 |
62 | h1,
63 | h2,
64 | h3,
65 | h4,
66 | h5,
67 | h6 {
68 | margin-top: 0;
69 | margin-bottom: 0.5rem;
70 | }
71 |
72 | p {
73 | margin-top: 0;
74 | margin-bottom: 1rem;
75 | }
76 |
77 | abbr[title],
78 | abbr[data-original-title] {
79 | text-decoration: underline;
80 | -webkit-text-decoration: underline dotted;
81 | text-decoration: underline dotted;
82 | cursor: help;
83 | border-bottom: 0;
84 | }
85 |
86 | address {
87 | margin-bottom: 1rem;
88 | font-style: normal;
89 | line-height: inherit;
90 | }
91 |
92 | ol,
93 | ul,
94 | dl {
95 | margin-top: 0;
96 | margin-bottom: 1rem;
97 | }
98 |
99 | ol ol,
100 | ul ul,
101 | ol ul,
102 | ul ol {
103 | margin-bottom: 0;
104 | }
105 |
106 | dt {
107 | font-weight: 700;
108 | }
109 |
110 | dd {
111 | margin-bottom: 0.5rem;
112 | margin-left: 0;
113 | }
114 |
115 | blockquote {
116 | margin: 0 0 1rem;
117 | }
118 |
119 | dfn {
120 | font-style: italic;
121 | }
122 |
123 | b,
124 | strong {
125 | font-weight: bolder;
126 | }
127 |
128 | small {
129 | font-size: 80%;
130 | }
131 |
132 | sub,
133 | sup {
134 | position: relative;
135 | font-size: 75%;
136 | line-height: 0;
137 | vertical-align: baseline;
138 | }
139 |
140 | sub {
141 | bottom: -0.25em;
142 | }
143 |
144 | sup {
145 | top: -0.5em;
146 | }
147 |
148 | a {
149 | color: #007bff;
150 | text-decoration: none;
151 | background-color: transparent;
152 | -webkit-text-decoration-skip: objects;
153 | }
154 |
155 | a:hover {
156 | color: #0056b3;
157 | text-decoration: underline;
158 | }
159 |
160 | a:not([href]):not([tabindex]) {
161 | color: inherit;
162 | text-decoration: none;
163 | }
164 |
165 | a:not([href]):not([tabindex]):hover,
166 | a:not([href]):not([tabindex]):focus {
167 | color: inherit;
168 | text-decoration: none;
169 | }
170 |
171 | a:not([href]):not([tabindex]):focus {
172 | outline: 0;
173 | }
174 |
175 | pre,
176 | code,
177 | kbd,
178 | samp {
179 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
180 | font-size: 1em;
181 | }
182 |
183 | pre {
184 | margin-top: 0;
185 | margin-bottom: 1rem;
186 | overflow: auto;
187 | -ms-overflow-style: scrollbar;
188 | }
189 |
190 | figure {
191 | margin: 0 0 1rem;
192 | }
193 |
194 | img {
195 | vertical-align: middle;
196 | border-style: none;
197 | }
198 |
199 | svg:not(:root) {
200 | overflow: hidden;
201 | }
202 |
203 | table {
204 | border-collapse: collapse;
205 | }
206 |
207 | caption {
208 | padding-top: 0.75rem;
209 | padding-bottom: 0.75rem;
210 | color: #6c757d;
211 | text-align: left;
212 | caption-side: bottom;
213 | }
214 |
215 | th {
216 | text-align: inherit;
217 | }
218 |
219 | label {
220 | display: inline-block;
221 | margin-bottom: 0.5rem;
222 | }
223 |
224 | button {
225 | border-radius: 0;
226 | }
227 |
228 | button:focus {
229 | outline: 1px dotted;
230 | outline: 5px auto -webkit-focus-ring-color;
231 | }
232 |
233 | input,
234 | button,
235 | select,
236 | optgroup,
237 | textarea {
238 | margin: 0;
239 | font-family: inherit;
240 | font-size: inherit;
241 | line-height: inherit;
242 | }
243 |
244 | button,
245 | input {
246 | overflow: visible;
247 | }
248 |
249 | button,
250 | select {
251 | text-transform: none;
252 | }
253 |
254 | button,
255 | html [type="button"],
256 | [type="reset"],
257 | [type="submit"] {
258 | -webkit-appearance: button;
259 | }
260 |
261 | button::-moz-focus-inner,
262 | [type="button"]::-moz-focus-inner,
263 | [type="reset"]::-moz-focus-inner,
264 | [type="submit"]::-moz-focus-inner {
265 | padding: 0;
266 | border-style: none;
267 | }
268 |
269 | input[type="radio"],
270 | input[type="checkbox"] {
271 | box-sizing: border-box;
272 | padding: 0;
273 | }
274 |
275 | input[type="date"],
276 | input[type="time"],
277 | input[type="datetime-local"],
278 | input[type="month"] {
279 | -webkit-appearance: listbox;
280 | }
281 |
282 | textarea {
283 | overflow: auto;
284 | resize: vertical;
285 | }
286 |
287 | fieldset {
288 | min-width: 0;
289 | padding: 0;
290 | margin: 0;
291 | border: 0;
292 | }
293 |
294 | legend {
295 | display: block;
296 | width: 100%;
297 | max-width: 100%;
298 | padding: 0;
299 | margin-bottom: 0.5rem;
300 | font-size: 1.5rem;
301 | line-height: inherit;
302 | color: inherit;
303 | white-space: normal;
304 | }
305 |
306 | progress {
307 | vertical-align: baseline;
308 | }
309 |
310 | [type="number"]::-webkit-inner-spin-button,
311 | [type="number"]::-webkit-outer-spin-button {
312 | height: auto;
313 | }
314 |
315 | [type="search"] {
316 | outline-offset: -2px;
317 | -webkit-appearance: none;
318 | }
319 |
320 | [type="search"]::-webkit-search-cancel-button,
321 | [type="search"]::-webkit-search-decoration {
322 | -webkit-appearance: none;
323 | }
324 |
325 | ::-webkit-file-upload-button {
326 | font: inherit;
327 | -webkit-appearance: button;
328 | }
329 |
330 | nb {
331 | display: inline-block;
332 | }
333 |
334 | summary {
335 | display: list-item;
336 | cursor: pointer;
337 | }
338 |
339 | template {
340 | display: none;
341 | }
342 |
343 | [hidden] {
344 | display: none !important;
345 | }
346 | /*# sourceMappingURL=bootstrap-reboot.css.map */
347 |
--------------------------------------------------------------------------------
/src/scss/core/_variables.scss:
--------------------------------------------------------------------------------
1 | // Colors
2 | $color-dark: #20252d;
3 | $color-white: #fff;
4 | $color-black: #000;
5 | $color-primary: #00bfaa;
6 | $color-grey: #eef0f2;
7 | $color-text: #4a4a4a;
8 |
9 | //Fonts
10 | $system-font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell,
11 | "Helvetica Neue", sans-serif;
12 |
13 | $main-font: "OpenSans", sans-serif;
14 |
--------------------------------------------------------------------------------
/src/scss/main.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.1.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2018 The Bootstrap Authors
4 | * Copyright 2011-2018 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box; }
12 |
13 | html {
14 | font-family: sans-serif;
15 | line-height: 1.15;
16 | -webkit-text-size-adjust: 100%;
17 | -ms-text-size-adjust: 100%;
18 | -ms-overflow-style: scrollbar;
19 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
20 |
21 | @-ms-viewport {
22 | width: device-width; }
23 |
24 | article,
25 | aside,
26 | figcaption,
27 | figure,
28 | footer,
29 | header,
30 | hgroup,
31 | main,
32 | nav,
33 | section {
34 | display: block; }
35 |
36 | body {
37 | margin: 0;
38 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
39 | font-size: 1rem;
40 | font-weight: 400;
41 | line-height: 1.5;
42 | color: #212529;
43 | text-align: left;
44 | background-color: #fff; }
45 |
46 | [tabindex="-1"]:focus {
47 | outline: 0 !important; }
48 |
49 | hr {
50 | box-sizing: content-box;
51 | height: 0;
52 | overflow: visible; }
53 |
54 | h1,
55 | h2,
56 | h3,
57 | h4,
58 | h5,
59 | h6 {
60 | margin-top: 0;
61 | margin-bottom: 0.5rem; }
62 |
63 | p {
64 | margin-top: 0;
65 | margin-bottom: 1rem; }
66 |
67 | abbr[title],
68 | abbr[data-original-title] {
69 | text-decoration: underline;
70 | -webkit-text-decoration: underline dotted;
71 | text-decoration: underline dotted;
72 | cursor: help;
73 | border-bottom: 0; }
74 |
75 | address {
76 | margin-bottom: 1rem;
77 | font-style: normal;
78 | line-height: inherit; }
79 |
80 | ol,
81 | ul,
82 | dl {
83 | margin-top: 0;
84 | margin-bottom: 1rem; }
85 |
86 | ol ol,
87 | ul ul,
88 | ol ul,
89 | ul ol {
90 | margin-bottom: 0; }
91 |
92 | dt {
93 | font-weight: 700; }
94 |
95 | dd {
96 | margin-bottom: 0.5rem;
97 | margin-left: 0; }
98 |
99 | blockquote {
100 | margin: 0 0 1rem; }
101 |
102 | dfn {
103 | font-style: italic; }
104 |
105 | b,
106 | strong {
107 | font-weight: bolder; }
108 |
109 | small {
110 | font-size: 80%; }
111 |
112 | sub,
113 | sup {
114 | position: relative;
115 | font-size: 75%;
116 | line-height: 0;
117 | vertical-align: baseline; }
118 |
119 | sub {
120 | bottom: -0.25em; }
121 |
122 | sup {
123 | top: -0.5em; }
124 |
125 | a {
126 | color: #007bff;
127 | text-decoration: none;
128 | background-color: transparent;
129 | -webkit-text-decoration-skip: objects; }
130 |
131 | a:hover {
132 | color: #0056b3;
133 | text-decoration: underline; }
134 |
135 | a:not([href]):not([tabindex]) {
136 | color: inherit;
137 | text-decoration: none; }
138 |
139 | a:not([href]):not([tabindex]):hover,
140 | a:not([href]):not([tabindex]):focus {
141 | color: inherit;
142 | text-decoration: none; }
143 |
144 | a:not([href]):not([tabindex]):focus {
145 | outline: 0; }
146 |
147 | pre,
148 | code,
149 | kbd,
150 | samp {
151 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
152 | font-size: 1em; }
153 |
154 | pre {
155 | margin-top: 0;
156 | margin-bottom: 1rem;
157 | overflow: auto;
158 | -ms-overflow-style: scrollbar; }
159 |
160 | figure {
161 | margin: 0 0 1rem; }
162 |
163 | img {
164 | vertical-align: middle;
165 | border-style: none; }
166 |
167 | svg:not(:root) {
168 | overflow: hidden; }
169 |
170 | table {
171 | border-collapse: collapse; }
172 |
173 | caption {
174 | padding-top: 0.75rem;
175 | padding-bottom: 0.75rem;
176 | color: #6c757d;
177 | text-align: left;
178 | caption-side: bottom; }
179 |
180 | th {
181 | text-align: inherit; }
182 |
183 | label {
184 | display: inline-block;
185 | margin-bottom: 0.5rem; }
186 |
187 | button {
188 | border-radius: 0; }
189 |
190 | button:focus {
191 | outline: 1px dotted;
192 | outline: 5px auto -webkit-focus-ring-color; }
193 |
194 | input,
195 | button,
196 | select,
197 | optgroup,
198 | textarea {
199 | margin: 0;
200 | font-family: inherit;
201 | font-size: inherit;
202 | line-height: inherit; }
203 |
204 | button,
205 | input {
206 | overflow: visible; }
207 |
208 | button,
209 | select {
210 | text-transform: none; }
211 |
212 | button,
213 | html [type="button"],
214 | [type="reset"],
215 | [type="submit"] {
216 | -webkit-appearance: button; }
217 |
218 | button::-moz-focus-inner,
219 | [type="button"]::-moz-focus-inner,
220 | [type="reset"]::-moz-focus-inner,
221 | [type="submit"]::-moz-focus-inner {
222 | padding: 0;
223 | border-style: none; }
224 |
225 | input[type="radio"],
226 | input[type="checkbox"] {
227 | box-sizing: border-box;
228 | padding: 0; }
229 |
230 | input[type="date"],
231 | input[type="time"],
232 | input[type="datetime-local"],
233 | input[type="month"] {
234 | -webkit-appearance: listbox; }
235 |
236 | textarea {
237 | overflow: auto;
238 | resize: vertical; }
239 |
240 | fieldset {
241 | min-width: 0;
242 | padding: 0;
243 | margin: 0;
244 | border: 0; }
245 |
246 | legend {
247 | display: block;
248 | width: 100%;
249 | max-width: 100%;
250 | padding: 0;
251 | margin-bottom: 0.5rem;
252 | font-size: 1.5rem;
253 | line-height: inherit;
254 | color: inherit;
255 | white-space: normal; }
256 |
257 | progress {
258 | vertical-align: baseline; }
259 |
260 | [type="number"]::-webkit-inner-spin-button,
261 | [type="number"]::-webkit-outer-spin-button {
262 | height: auto; }
263 |
264 | [type="search"] {
265 | outline-offset: -2px;
266 | -webkit-appearance: none; }
267 |
268 | [type="search"]::-webkit-search-cancel-button,
269 | [type="search"]::-webkit-search-decoration {
270 | -webkit-appearance: none; }
271 |
272 | ::-webkit-file-upload-button {
273 | font: inherit;
274 | -webkit-appearance: button; }
275 |
276 | nb {
277 | display: inline-block; }
278 |
279 | summary {
280 | display: list-item;
281 | cursor: pointer; }
282 |
283 | template {
284 | display: none; }
285 |
286 | [hidden] {
287 | display: none !important; }
288 |
289 | /*# sourceMappingURL=bootstrap-reboot.css.map */
290 | @font-face {
291 | font-family: "OpenSans";
292 | font-style: normal;
293 | font-weight: 300;
294 | src: url("../assets/fonts/OpenSans/OpenSans-Light.ttf") format("truetype");
295 | text-rendering: optimizeLegibility; }
296 |
297 | @font-face {
298 | font-family: "OpenSans";
299 | font-style: normal;
300 | font-weight: normal;
301 | src: url("../assets/fonts/OpenSans/OpenSans-Regular.ttf") format("truetype");
302 | text-rendering: optimizeLegibility; }
303 |
304 | @font-face {
305 | font-family: "OpenSans";
306 | font-style: normal;
307 | font-weight: 600;
308 | src: url("../assets/fonts/OpenSans/OpenSans-SemiBold.ttf") format("truetype");
309 | text-rendering: optimizeLegibility; }
310 |
311 | @font-face {
312 | font-family: "OpenSans";
313 | font-style: normal;
314 | font-weight: bold;
315 | src: url("../assets/fonts/OpenSans/OpenSans-Bold.ttf") format("truetype");
316 | text-rendering: optimizeLegibility; }
317 |
318 | @font-face {
319 | font-family: "OpenSans";
320 | font-style: normal;
321 | font-weight: 800;
322 | src: url("../assets/fonts/OpenSans/OpenSans-ExtraBold.ttf") format("truetype");
323 | text-rendering: optimizeLegibility; }
324 |
325 | .d-none {
326 | display: none; }
327 |
328 | html {
329 | font-size: 62.5%; }
330 |
331 | body {
332 | -webkit-box-sizing: border-box;
333 | -moz-box-sizing: border-box;
334 | box-sizing: border-box;
335 | font-family: "OpenSans", sans-serif;
336 | font-size: 1.6rem; }
337 |
338 | .home {
339 | background: #eef0f2;
340 | transition: background 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
341 | .home__container {
342 | display: flex;
343 | padding: 3rem 5rem;
344 | flex-direction: column;
345 | justify-content: space-between;
346 | min-height: 100vh; }
347 | @media (max-width: 575px) {
348 | .home__container {
349 | padding: 3rem; } }
350 | .home.dark {
351 | background: #20252d; }
352 | .home.dark .dark-white {
353 | color: #fff !important; }
354 | .home.dark .board {
355 | background: rgba(255, 255, 255, 0.2) !important; }
356 | .home.dark .dark-grey {
357 | color: rgba(255, 255, 255, 0.8) !important; }
358 | .home .container {
359 | display: flex;
360 | width: 100%; }
361 | @media (min-width: 992px) and (max-width: 1199px) {
362 | .home .container {
363 | max-width: 1140px;
364 | margin: 0 auto; } }
365 | @media (min-width: 1200px) {
366 | .home .container {
367 | max-width: 1400px;
368 | margin: 0 auto; } }
369 | .home .row {
370 | display: flex;
371 | flex-direction: row; }
372 | @media (max-width: 991px) {
373 | .home .row {
374 | flex-direction: column; } }
375 | .home .row .col {
376 | flex: 1;
377 | padding: 0 2rem; }
378 | .home .row .col-5 {
379 | width: calc((100% / 12) * 5); }
380 | @media (max-width: 991px) {
381 | .home .row .col-5 {
382 | width: 100%;
383 | padding: 0; } }
384 | .home .row .col-7 {
385 | width: calc((100% / 12) * 7); }
386 | @media (max-width: 991px) {
387 | .home .row .col-7 {
388 | width: 100%;
389 | padding: 0; } }
390 | @media (max-width: 991px) {
391 | .home .row .col {
392 | flex: 1;
393 | padding: 0; } }
394 | .home .content {
395 | flex: 1;
396 | padding-top: 10rem; }
397 | .home .content__title {
398 | color: #20252d;
399 | letter-spacing: 1px; }
400 | .home .content__title span {
401 | color: #00bfaa; }
402 | @media (max-width: 575px) {
403 | .home .content {
404 | padding-top: 5rem; } }
405 | .home .content__subtitle {
406 | color: #4a4a4a;
407 | font-size: 1.4rem;
408 | letter-spacing: 1px;
409 | margin: 0;
410 | transition: 0.1s color;
411 | width: 30rem; }
412 | @media (max-width: 575px) {
413 | .home .content__subtitle {
414 | width: 100%; } }
415 | .home .content .options {
416 | margin: 5rem 0; }
417 | .home .content .options__title {
418 | color: #4a4a4a;
419 | font-size: 1.4rem;
420 | letter-spacing: 1px;
421 | margin: 0;
422 | transition: 0.1s color;
423 | color: #00bfaa;
424 | font-weight: bold;
425 | margin-bottom: 2rem; }
426 | .home .content .options-select {
427 | width: 80%;
428 | margin-bottom: 2rem; }
429 | @media (max-width: 991px) {
430 | .home .content .options-select {
431 | width: 100%; } }
432 | .home .content .options-select__value-container {
433 | padding-left: 1.5rem; }
434 | .home .content .options-select__control {
435 | height: 5rem;
436 | border: none;
437 | box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.1); }
438 | .home .content .options-select__indicator-separator {
439 | display: none; }
440 | .home .content .options-select__dropdown-indicator {
441 | padding-right: 1.5rem; }
442 | .home .content .options-select__single-value {
443 | color: #4a4a4a;
444 | font-size: 1.4rem;
445 | letter-spacing: 1px;
446 | margin: 0;
447 | transition: 0.1s color;
448 | font-weight: bold; }
449 | .home .content .options-select__menu {
450 | margin: 0;
451 | padding: 0 !important;
452 | top: 90%; }
453 | .home .content .options-select__menu-list {
454 | padding: 0 !important; }
455 | @media (max-width: 991px) {
456 | .home .content .boards {
457 | margin-bottom: 15rem; } }
458 | .home .content .board {
459 | background: #20252d;
460 | border-radius: 1rem;
461 | border-left: 1rem solid #00bfaa;
462 | display: flex;
463 | flex-direction: row;
464 | justify-content: space-between;
465 | padding: 3rem;
466 | transition: 0.3s background cubic-bezier(0.175, 0.885, 0.32, 1.275); }
467 | .home .content .board .faded {
468 | opacity: 0.5; }
469 | .home .content .board pre {
470 | margin: 0; }
471 | .home .content .board__title {
472 | color: #20252d;
473 | letter-spacing: 1px;
474 | margin-bottom: 1rem; }
475 | .home .content .board--2 .Typist {
476 | font-weight: normal; }
477 | .home .content .board__group--2 {
478 | margin-top: 5rem; }
479 | @media (max-width: 575px) {
480 | .home .content .board {
481 | padding: 2rem; } }
482 | .home .content .board * {
483 | color: #fff;
484 | letter-spacing: 1px;
485 | font-weight: 600; }
486 |
487 | .Typist {
488 | white-space: pre-wrap; }
489 |
490 | .copy {
491 | position: relative;
492 | display: inline-block; }
493 | .copy__image {
494 | cursor: pointer;
495 | position: relative;
496 | width: 2rem; }
497 | .copy__popover {
498 | background: #fff;
499 | border-radius: 0.3rem;
500 | bottom: 50%;
501 | color: #20252d !important;
502 | display: inline-block;
503 | font-size: 1rem;
504 | padding: 0.2rem 0.5rem;
505 | position: absolute;
506 | opacity: 0;
507 | right: 50%;
508 | text-align: center;
509 | text-transform: capitalize;
510 | transform: translateX(50%);
511 | transition: all 0.3s; }
512 | .copy__popover.show {
513 | opacity: 1;
514 | bottom: 150%; }
515 | .copy__popover::after {
516 | border: 5px transparent solid;
517 | border-top-color: #fff;
518 | content: '';
519 | display: block;
520 | left: 50%;
521 | position: absolute;
522 | transform: translateX(-50%); }
523 |
524 | .toggle {
525 | display: flex;
526 | justify-content: flex-start;
527 | align-items: center; }
528 | .toggle__option {
529 | color: #4a4a4a;
530 | font-size: 1.4rem;
531 | letter-spacing: 1px;
532 | margin: 0;
533 | transition: 0.1s color;
534 | transition: all 0.3s; }
535 | .toggle__option--left {
536 | margin-right: 1rem; }
537 | .toggle__option--right {
538 | margin-left: 1rem; }
539 | @media (max-width: 575px) {
540 | .toggle {
541 | margin-bottom: 2rem; } }
542 |
543 | .toggler {
544 | display: inline-block;
545 | margin: 7px;
546 | margin: 2.5px;
547 | width: 45px;
548 | height: 10px;
549 | text-align: center;
550 | position: relative; }
551 | .toggler input[type='checkbox'] {
552 | display: none; }
553 | .toggler input[type='checkbox']:checked ~ .button {
554 | background: #fff;
555 | left: 25px;
556 | transition: 0.5s; }
557 | .toggler input[type='checkbox']:checked ~ .switch {
558 | background: #00baa5;
559 | transition: 0.5s; }
560 | .toggler .switch {
561 | display: block;
562 | width: 45px;
563 | height: 10px;
564 | background: #00bfaa;
565 | border-radius: 5px;
566 | position: absolute;
567 | top: 0;
568 | left: 0;
569 | transition: 0.5s;
570 | cursor: pointer; }
571 | .toggler .button {
572 | height: 20px;
573 | width: 20px;
574 | border-radius: 50%;
575 | background: white;
576 | position: absolute;
577 | top: -5px;
578 | left: 0;
579 | box-shadow: 0 0.9px 1.8px rgba(0, 0, 0, 0.4);
580 | transition: 0.5s;
581 | cursor: pointer; }
582 |
583 | .nav {
584 | align-items: center;
585 | display: flex;
586 | justify-content: space-between; }
587 | @media (max-width: 575px) {
588 | .nav {
589 | align-items: center;
590 | flex-direction: column;
591 | justify-content: center; } }
592 | .nav .language {
593 | align-items: center;
594 | display: flex;
595 | margin-right: 4rem; }
596 | @media (max-width: 575px) {
597 | .nav .language {
598 | margin-right: 0;
599 | margin-bottom: 2rem; } }
600 | .nav .language__title {
601 | color: #4a4a4a;
602 | font-size: 1.4rem;
603 | letter-spacing: 1px;
604 | margin: 0;
605 | transition: 0.1s color; }
606 | .nav .language__select {
607 | width: 15rem;
608 | margin-left: 3rem; }
609 | .nav .language__select__control {
610 | border: none;
611 | box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.1); }
612 | .nav .language__select__indicator-separator {
613 | display: none; }
614 | .nav .language__select__single-value {
615 | color: #4a4a4a;
616 | font-size: 1.4rem;
617 | letter-spacing: 1px;
618 | margin: 0;
619 | transition: 0.1s color; }
620 | .nav .language__select__menu {
621 | margin: 0;
622 | padding: 0 !important; }
623 | .nav .language__select__menu-list {
624 | padding: 0 !important; }
625 |
626 | .footer {
627 | margin-top: 2rem; }
628 | .footer__copyright {
629 | display: block;
630 | color: #4a4a4a;
631 | font-size: 1.4rem;
632 | letter-spacing: 1px;
633 | margin: 0;
634 | transition: 0.1s color;
635 | text-align: center;
636 | line-height: 4rem; }
637 | .footer__copyright span {
638 | color: crimson; }
639 | .footer__copyright:hover {
640 | color: initial; }
641 | .footer__copyright a {
642 | color: inherit; }
643 | .footer__copyright a:hover {
644 | text-decoration: underline; }
645 | .footer .logo {
646 | float: right; }
647 | @media (max-width: 768px) {
648 | .footer .logo {
649 | justify-content: center;
650 | margin-bottom: 1rem; } }
651 | .footer .logo--github {
652 | width: 4rem;
653 | height: 4rem;
654 | fill: blue; }
655 | .footer__link {
656 | margin-left: 2rem;
657 | position: relative; }
658 | .footer__link::before {
659 | content: '';
660 | display: inline-block;
661 | width: 3px;
662 | height: 3px;
663 | border-radius: 100%;
664 | background-color: white;
665 | position: absolute;
666 | top: 50%;
667 | transform: translateY(-50%);
668 | left: -1.2rem; }
669 |
--------------------------------------------------------------------------------
/src/scss/main.scss:
--------------------------------------------------------------------------------
1 | // Core & Helpers
2 | @import 'core/reboot';
3 | @import 'core/variables';
4 | @import 'core/mixins';
5 | @import 'core/fonts';
6 |
7 | // Utilities
8 | @import 'utilities/utils';
9 | @import 'utilities/text';
10 |
11 | //pages
12 | @import 'pages/home';
13 |
14 | //components
15 | @import 'components/copy';
16 | @import 'components/toggle';
17 | @import 'components/nav';
18 | @import 'components/footer';
19 |
20 | //animations
21 |
22 | @import 'utilities/overrides';
23 |
--------------------------------------------------------------------------------
/src/scss/pages/_home.scss:
--------------------------------------------------------------------------------
1 | .home {
2 | background: $color-grey;
3 | transition: background 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
4 |
5 | &__container {
6 | display: flex;
7 | padding: 3rem 5rem;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | min-height: 100vh;
11 |
12 | @include respond('xs') {
13 | padding: 3rem;
14 | }
15 | }
16 |
17 | &.dark {
18 | background: $color-dark;
19 |
20 | .dark-white {
21 | color: $color-white !important;
22 | }
23 |
24 | .board {
25 | background: rgba($color-white, 0.2) !important;
26 | }
27 |
28 | .dark-grey {
29 | color: rgba($color-white, 0.8) !important;
30 | }
31 | }
32 |
33 | .container {
34 | display: flex;
35 | width: 100%;
36 | @include respond('lg') {
37 | max-width: 1140px;
38 | margin: 0 auto;
39 | }
40 |
41 | @include respond('xl') {
42 | max-width: 1400px;
43 | margin: 0 auto;
44 | }
45 | }
46 |
47 | .row {
48 | display: flex;
49 | flex-direction: row;
50 |
51 | @include respond('am') {
52 | flex-direction: column;
53 | }
54 |
55 | .col {
56 | flex: 1;
57 | padding: 0 2rem;
58 |
59 | &-5 {
60 | width: calc((100% / 12) * 5);
61 | @include respond('am') {
62 | width: 100%;
63 | padding: 0;
64 | }
65 | }
66 |
67 | &-7 {
68 | width: calc((100% / 12) * 7);
69 | @include respond('am') {
70 | width: 100%;
71 | padding: 0;
72 | }
73 | }
74 |
75 | @include respond('am') {
76 | flex: 1;
77 | padding: 0;
78 | }
79 | }
80 | }
81 |
82 | .content {
83 | flex: 1;
84 | padding-top: 10rem;
85 |
86 | &__title {
87 | color: $color-dark;
88 | letter-spacing: 1px;
89 |
90 | span {
91 | color: $color-primary;
92 | }
93 | }
94 |
95 | @include respond('xs') {
96 | padding-top: 5rem;
97 | }
98 |
99 | &__subtitle {
100 | @include text();
101 | width: 30rem;
102 |
103 | @include respond('xs') {
104 | width: 100%;
105 | }
106 | }
107 |
108 | .options {
109 | margin: 5rem 0;
110 | &__title {
111 | @include text();
112 | color: $color-primary;
113 | font-weight: bold;
114 | margin-bottom: 2rem;
115 | }
116 |
117 | &-select {
118 | width: 80%;
119 | margin-bottom: 2rem;
120 |
121 | @include respond('am') {
122 | width: 100%;
123 | }
124 |
125 | &__value-container {
126 | padding-left: 1.5rem;
127 | }
128 |
129 | &__control {
130 | height: 5rem;
131 | border: none;
132 | box-shadow: 1px 2px 2px rgba($color-black, 0.1);
133 | }
134 |
135 | &__indicator-separator {
136 | display: none;
137 | }
138 |
139 | &__dropdown-indicator {
140 | padding-right: 1.5rem;
141 | }
142 |
143 | &__single-value {
144 | @include text();
145 | font-weight: bold;
146 | }
147 |
148 | &__menu {
149 | margin: 0;
150 | padding: 0 !important;
151 | top: 90%;
152 |
153 | &-list {
154 | padding: 0 !important;
155 | }
156 | }
157 | }
158 | }
159 |
160 | .boards {
161 | @include respond('am') {
162 | margin-bottom: 15rem;
163 | }
164 | }
165 |
166 | .board {
167 | background: $color-dark;
168 | border-radius: 1rem;
169 | border-left: 1rem solid $color-primary;
170 | display: flex;
171 | flex-direction: row;
172 | justify-content: space-between;
173 | padding: 3rem;
174 | transition: 0.3s background cubic-bezier(0.175, 0.885, 0.32, 1.275);
175 |
176 | .faded {
177 | opacity: 0.5;
178 | }
179 |
180 | pre {
181 | margin: 0;
182 | }
183 |
184 | &__title {
185 | color: $color-dark;
186 | letter-spacing: 1px;
187 | margin-bottom: 1rem;
188 | }
189 |
190 | &--2 {
191 | .Typist {
192 | font-weight: normal;
193 | }
194 | }
195 |
196 | &__group {
197 | &--2 {
198 | margin-top: 5rem;
199 | }
200 | }
201 |
202 | @include respond('xs') {
203 | padding: 2rem;
204 | }
205 |
206 | * {
207 | color: $color-white;
208 | letter-spacing: 1px;
209 | font-weight: 600;
210 | }
211 | }
212 | }
213 | }
214 |
215 | .Typist {
216 | white-space: pre-wrap;
217 | }
218 |
--------------------------------------------------------------------------------
/src/scss/utilities/_overrides.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/summitech/gitexplorer/ffe8b11b692ee93aa07078d105a9a2dab07e50f7/src/scss/utilities/_overrides.scss
--------------------------------------------------------------------------------
/src/scss/utilities/_text.scss:
--------------------------------------------------------------------------------
1 | html {
2 | font-size: 62.5%;
3 | }
4 |
5 | body {
6 | -webkit-box-sizing: border-box;
7 | -moz-box-sizing: border-box;
8 | box-sizing: border-box;
9 | font-family: $main-font;
10 | font-size: 1.6rem;
11 | }
12 |
--------------------------------------------------------------------------------
/src/scss/utilities/_utils.scss:
--------------------------------------------------------------------------------
1 | .d-none {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read http://bit.ly/CRA-PWA.
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost'
15 | // [::1] is the IPv6 localhost address.
16 | || window.location.hostname === '[::1]'
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | || window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service '
46 | + 'worker. To learn more, visit http://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then((registration) => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | installingWorker.onstatechange = () => {
64 | if (installingWorker.state === 'installed') {
65 | if (navigator.serviceWorker.controller) {
66 | // At this point, the updated precached content has been fetched,
67 | // but the previous service worker will still serve the older
68 | // content until all client tabs are closed.
69 | console.log(
70 | 'New content is available and will be used when all '
71 | + 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
72 | );
73 |
74 | // Execute callback
75 | if (config && config.onUpdate) {
76 | config.onUpdate(registration);
77 | }
78 | } else {
79 | // At this point, everything has been precached.
80 | // It's the perfect time to display a
81 | // "Content is cached for offline use." message.
82 | console.log('Content is cached for offline use.');
83 |
84 | // Execute callback
85 | if (config && config.onSuccess) {
86 | config.onSuccess(registration);
87 | }
88 | }
89 | }
90 | };
91 | };
92 | })
93 | .catch((error) => {
94 | console.error('Error during service worker registration:', error);
95 | });
96 | }
97 |
98 | function checkValidServiceWorker(swUrl, config) {
99 | // Check if the service worker can be found. If it can't reload the page.
100 | fetch(swUrl)
101 | .then((response) => {
102 | // Ensure service worker exists, and that we really are getting a JS file.
103 | if (
104 | response.status === 404
105 | || response.headers.get('content-type').indexOf('javascript') === -1
106 | ) {
107 | // No service worker found. Probably a different app. Reload the page.
108 | navigator.serviceWorker.ready.then((registration) => {
109 | registration.unregister().then(() => {
110 | window.location.reload();
111 | });
112 | });
113 | } else {
114 | // Service worker found. Proceed as normal.
115 | registerValidSW(swUrl, config);
116 | }
117 | })
118 | .catch(() => {
119 | console.log(
120 | 'No internet connection found. App is running in offline mode.'
121 | );
122 | });
123 | }
124 |
125 | export function unregister() {
126 | if ('serviceWorker' in navigator) {
127 | navigator.serviceWorker.ready.then((registration) => {
128 | registration.unregister();
129 | });
130 | }
131 | }
132 |
--------------------------------------------------------------------------------