├── .babelrc
├── .eslintrc.json
├── .gitignore
├── .nojekyll
├── 404.html
├── LICENSE
├── README.md
├── build
├── assets
│ ├── color.c7a33805ffda0d32bd2a9904c8b02750.png
│ ├── fontawesome-webfont.674f50d287a8c48dc19ba404d20fe713.eot
│ ├── fontawesome-webfont.912ec66d7572ff821749319396470bde.svg
│ ├── fontawesome-webfont.af7ae505a9eed503f8b8e6982036873e.woff2
│ ├── fontawesome-webfont.b06871f281fee6b241d60582ae9369b9.ttf
│ ├── fontawesome-webfont.fee66e712a8a08eef5805a46892932ad.woff
│ ├── hue.0614c27197fc3ce572e161840d23b2af.png
│ ├── line.567f57385ea3dde2c9aec797d07850d2.gif
│ ├── loading.8732a6660b528fadfaeb35bcf568875f.gif
│ ├── password-meter.64ca45e5df0f0261431766d0701ac7b3.png
│ ├── roboto-v15-latin-regular.16e1d930cf13fb7a956372044b6d02d0.woff
│ ├── roboto-v15-latin-regular.38861cba61c66739c1452c3a71e39852.ttf
│ ├── roboto-v15-latin-regular.3d3a53586bd78d1069ae4b89a3b9aa98.svg
│ ├── roboto-v15-latin-regular.7e367be02cd17a96d513ab74846bafb3.woff2
│ ├── roboto-v15-latin-regular.9f916e330c478bbfa2a0dd6614042046.eot
│ └── slider_handles.1868e2550c9853a938a6211d196f9dcd.png
└── bundle.js
├── index.html
├── package-lock.json
├── package.json
├── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── registerServiceWorker.js
├── services
│ └── github-api.js
└── views
│ ├── FollowerItem.js
│ ├── Followers.js
│ ├── Following.js
│ ├── FollowingItem.js
│ ├── Github.js
│ ├── Repositories.js
│ ├── RepositoryFilter.js
│ ├── RepositoryItem.js
│ ├── Search.js
│ ├── StarItem.js
│ ├── Stars.js
│ └── UserProfile.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env", "react", "stage-1"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "babel-eslint",
4 | "extends": "airbnb",
5 | "env": {
6 | "browser": true
7 | },
8 | "rules": {
9 | "no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true }],
10 | "no-plusplus": "off",
11 | "import/no-extraneous-dependencies": ["error", {"devDependencies": ["./webpack.config.js"]}],
12 | "react/forbid-prop-types": "off",
13 | "react/jsx-filename-extension": "off",
14 | "react/no-array-index-key": "off"
15 | },
16 | "parserOptions": {
17 | "ecmaFeatures": {
18 | "experimentalObjectRestSpread": true
19 | }
20 | },
21 | "plugins": [
22 | "react"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependency directory
2 | node_modules
3 |
4 | # Source maps
5 | *.js.map
6 |
7 | # Files marked with gitigx
8 | *gitigx*
9 |
10 | # idea
11 | .idea
12 |
--------------------------------------------------------------------------------
/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/.nojekyll
--------------------------------------------------------------------------------
/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ReactJS Github viewer
6 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Sudheer Jonna
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 | ## React Github Viewer using React, Axios and PrimeReact
2 |
3 | ### How to build and run
4 | ``npm install``
5 | ``npm start``
6 |
7 | ## Demo
8 | http://sudheerj.github.io/react-github
9 |
--------------------------------------------------------------------------------
/build/assets/color.c7a33805ffda0d32bd2a9904c8b02750.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/color.c7a33805ffda0d32bd2a9904c8b02750.png
--------------------------------------------------------------------------------
/build/assets/fontawesome-webfont.674f50d287a8c48dc19ba404d20fe713.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/fontawesome-webfont.674f50d287a8c48dc19ba404d20fe713.eot
--------------------------------------------------------------------------------
/build/assets/fontawesome-webfont.af7ae505a9eed503f8b8e6982036873e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/fontawesome-webfont.af7ae505a9eed503f8b8e6982036873e.woff2
--------------------------------------------------------------------------------
/build/assets/fontawesome-webfont.b06871f281fee6b241d60582ae9369b9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/fontawesome-webfont.b06871f281fee6b241d60582ae9369b9.ttf
--------------------------------------------------------------------------------
/build/assets/fontawesome-webfont.fee66e712a8a08eef5805a46892932ad.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/fontawesome-webfont.fee66e712a8a08eef5805a46892932ad.woff
--------------------------------------------------------------------------------
/build/assets/hue.0614c27197fc3ce572e161840d23b2af.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/hue.0614c27197fc3ce572e161840d23b2af.png
--------------------------------------------------------------------------------
/build/assets/line.567f57385ea3dde2c9aec797d07850d2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/line.567f57385ea3dde2c9aec797d07850d2.gif
--------------------------------------------------------------------------------
/build/assets/loading.8732a6660b528fadfaeb35bcf568875f.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/loading.8732a6660b528fadfaeb35bcf568875f.gif
--------------------------------------------------------------------------------
/build/assets/password-meter.64ca45e5df0f0261431766d0701ac7b3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/password-meter.64ca45e5df0f0261431766d0701ac7b3.png
--------------------------------------------------------------------------------
/build/assets/roboto-v15-latin-regular.16e1d930cf13fb7a956372044b6d02d0.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/roboto-v15-latin-regular.16e1d930cf13fb7a956372044b6d02d0.woff
--------------------------------------------------------------------------------
/build/assets/roboto-v15-latin-regular.38861cba61c66739c1452c3a71e39852.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/roboto-v15-latin-regular.38861cba61c66739c1452c3a71e39852.ttf
--------------------------------------------------------------------------------
/build/assets/roboto-v15-latin-regular.3d3a53586bd78d1069ae4b89a3b9aa98.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
309 |
--------------------------------------------------------------------------------
/build/assets/roboto-v15-latin-regular.7e367be02cd17a96d513ab74846bafb3.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/roboto-v15-latin-regular.7e367be02cd17a96d513ab74846bafb3.woff2
--------------------------------------------------------------------------------
/build/assets/roboto-v15-latin-regular.9f916e330c478bbfa2a0dd6614042046.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/roboto-v15-latin-regular.9f916e330c478bbfa2a0dd6614042046.eot
--------------------------------------------------------------------------------
/build/assets/slider_handles.1868e2550c9853a938a6211d196f9dcd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sudheerj/react-github/32c98b1cea6a155cf6262c57ca86b512fb4f8903/build/assets/slider_handles.1868e2550c9853a938a6211d196f9dcd.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ReactJS Github viewer
7 |
8 |
9 |
10 |
11 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-github",
3 | "version": "0.0.1",
4 | "private": true,
5 | "homepage": "https://sudheerj.github.io/react-github",
6 | "description": "Reactjs githubviewer",
7 | "scripts": {
8 | "start": "webpack-dev-server --devtool eval-source-map --history-api-fallback --open",
9 | "build": "webpack -p"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/sudheerj/react-github.git"
14 | },
15 | "author": "Sudheer Jonna ",
16 | "license": "MIT",
17 | "dependencies": {
18 | "axios": "0.13.1",
19 | "bootstrap": "^3.3.5",
20 | "classnames": "^2.2.5",
21 | "font-awesome": "^4.7.0",
22 | "gh-pages": "^1.1.0",
23 | "history": "^3.0.0",
24 | "moment": "^2.10.6",
25 | "primereact": "^1.4.0",
26 | "prop-types": "^15.6.0",
27 | "react": "^16.2.0",
28 | "react-dom": "^16.2.0",
29 | "react-router": "^4.2.0",
30 | "react-router-dom": "^4.2.2",
31 | "react-scripts": "1.1.1"
32 | },
33 | "devDependencies": {
34 | "babel-core": "^6.26.0",
35 | "babel-eslint": "^7.2.3",
36 | "babel-loader": "^7.1.2",
37 | "babel-preset-env": "^1.6.0",
38 | "babel-preset-react": "^6.24.1",
39 | "babel-preset-stage-1": "^6.24.1",
40 | "eslint": "^3.19.0",
41 | "eslint-config-airbnb": "^14.1.0",
42 | "eslint-plugin-import": "^2.2.0",
43 | "eslint-plugin-jsx-a11y": "^4.0.0",
44 | "eslint-plugin-react": "^6.10.3",
45 | "webpack": "^3.6.0",
46 | "webpack-dev-server": "^2.8.2"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-title {
18 | font-size: 1.5em;
19 | }
20 |
21 | .App-intro {
22 | font-size: large;
23 | }
24 |
25 | @keyframes App-logo-spin {
26 | from { transform: rotate(0deg); }
27 | to { transform: rotate(360deg); }
28 | }
29 |
30 | a {
31 | color: #0366d6;
32 | text-decoration: none;
33 | }
34 |
35 | .content-wrapper {
36 | padding: 3em 7em 1em 7em;
37 | }
38 |
39 | h1 {
40 | font-size: 32px;
41 | font-weight: 600;
42 | }
43 |
44 | .vcard-names {
45 | line-height: 1;
46 | }
47 | .vcard-fullname {
48 | font-size: 26px;
49 | line-height: 30px;
50 | }
51 | .vcard-username {
52 | font-size: 20px;
53 | font-style: normal;
54 | font-weight: 300;
55 | line-height: 24px;
56 | color: #666;
57 | }
58 |
59 | .d-block {
60 | display: block !important;
61 | }
62 |
63 | .overflow-hidden {
64 | overflow: hidden !important;
65 | }
66 |
67 | .py-3 {
68 | padding-top: 16px !important;
69 | padding-bottom: 16px !important;
70 | }
71 |
72 | .border-top {
73 | border-top: 1px #e1e4e8 solid !important;
74 | }
75 |
76 | .avatar {
77 | display: inline-block;
78 | overflow: hidden;
79 | line-height: 1;
80 | vertical-align: middle;
81 | border-radius: 3px;
82 | }
83 |
84 | .h4 {
85 | font-size: 16px !important;
86 | }
87 |
88 | .mb-1 {
89 | margin-bottom: 4px !important;
90 | }
91 |
92 | .user-profile-bio {
93 | margin-bottom: 12px;
94 | overflow: hidden;
95 | font-size: 14px;
96 | color: #6a737d;
97 | }
98 |
99 | body {
100 | min-width: 1020px;
101 | word-wrap: break-word;
102 | }
103 |
104 | .width-full {
105 | width: 100% !important;
106 | }
107 | @media (min-width: 768px)
108 | .form-control, .form-select {
109 | font-size: 14px;
110 | }
111 | .form-control, .form-select {
112 | min-height: 34px;
113 | padding: 6px 8px;
114 | font-size: 16px;
115 | line-height: 20px;
116 | color: #24292e;
117 | vertical-align: middle;
118 | background-color: #fff;
119 | background-repeat: no-repeat;
120 | background-position: right 8px center;
121 | border: 1px solid #d1d5da;
122 | border-radius: 3px;
123 | outline: none;
124 | box-shadow: inset 0 1px 2px rgba(27,31,35,0.075);
125 | width: 400px;
126 | }
127 |
128 | .list-unstyled {
129 | padding-left: 0;
130 | list-style: none;
131 | }
132 |
133 | .link-gray-dark {
134 | color: #24292e !important;
135 | }
136 |
137 | .f4 {
138 | font-size: 16px !important;
139 | }
140 |
141 | .text-gray {
142 | color: #586069 !important;
143 | }
144 |
145 | .f6 {
146 | font-size: 12px !important;
147 | }
148 |
149 | .py-1 {
150 | padding-top: 4px !important;
151 | padding-bottom: 4px !important;
152 | }
153 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 |
5 | class App extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 | Welcome to React
12 |
13 |
14 | To get started, edit src/App.js
and save to reload.
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | form.home {
8 | padding-top: 300px;
9 | padding-left: 500px;
10 |
11 | }
12 |
13 | .user-profile-bio {
14 | margin-bottom: 12px;
15 | overflow: hidden;
16 | font-size: 14px;
17 | color: #6a737d;
18 | }
19 |
20 | body {
21 | color: #666;
22 | }
23 | time, strong, small {
24 | color: #888;
25 | }
26 | strong {
27 | margin-left: 10px;
28 | }
29 | h2, h4 {
30 | color: #333;
31 | }
32 | h5 {
33 | font-weight: 300;
34 | font-size: 20px;
35 | }
36 | li {
37 | padding: 25px 0;
38 | }
39 | section {
40 | padding: 20px 0;
41 | }
42 |
43 | .border-bottom {
44 | border-bottom: 1px solid #eee;
45 | }
46 |
47 | section.home {
48 | padding-top: 200px;
49 | text-align: center;
50 | }
51 | section.home button {
52 | border-top-left-radius: 0;
53 | border-bottom-left-radius: 0;
54 | }
55 |
56 | section.stats {
57 | text-align: center;
58 | }
59 | section.stats span {
60 | display: inline-block;
61 | width: 80px;
62 | }
63 | section.stats h2 {
64 | margin: 0;
65 | }
66 |
67 | section.orgs img {
68 | border-radius: 3px;
69 | margin: 5px;
70 | width: 42px;
71 | height: 42px;
72 | }
73 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import 'primereact/resources/primereact.min.css';
2 | import 'primereact/resources/themes/omega/theme.css';
3 | import 'font-awesome/css/font-awesome.css';
4 |
5 | import React from 'react' ;
6 | import ReactDOM from 'react-dom' ;
7 | import { BrowserRouter as Router, Route } from 'react-router-dom';
8 | import './index.css';
9 | import Search from './views/Search';
10 | import Github from './views/Github';
11 |
12 |
13 |
14 | ReactDOM.render(
15 |
16 |
17 |
18 |
19 |
20 |
21 | , document.getElementById('root')
22 | );
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/services/github-api.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | const BASE_URL = 'https://api.github.com';
4 |
5 | export {getRepositories, getUserData, getStars, getFollowers, getFollowing};
6 |
7 | function getRepositories(username) {
8 | const url = `${BASE_URL}/users/${username}/repos?per_page=250`;
9 | return axios.get(url).then(response => response.data);
10 | }
11 |
12 | function getStars(username) {
13 | const url = `${BASE_URL}/users/${username}/starred?per_page=250`;
14 | return axios.get(url).then(response => response.data);
15 | }
16 |
17 | function getFollowers(username) {
18 | const url = `${BASE_URL}/users/${username}/followers?per_page=250`;
19 | return axios.get(url).then(response => response.data);
20 | }
21 |
22 | function getFollowing(username) {
23 | const url = `${BASE_URL}/users/${username}/following?per_page=250`;
24 | return axios.get(url).then(response => response.data);
25 | }
26 |
27 | function getUserData(username) {
28 | return axios.all([
29 | axios.get(`${BASE_URL}/users/${username}`),
30 | axios.get(`${BASE_URL}/users/${username}/orgs`),
31 | ])
32 | .then(([user, orgs]) => ({
33 | user: user.data,
34 | orgs: orgs.data,
35 | }));
36 | }
37 |
--------------------------------------------------------------------------------
/src/views/FollowerItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default FollowerItem;
5 |
6 | function FollowerItem({follower}) {
7 | return (
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 | {follower.name}
23 | {follower.login}
24 |
25 |
26 | );
27 | }
28 |
29 | FollowerItem.propTypes = {
30 | follower: PropTypes.shape({
31 | pushed_at: PropTypes.string,
32 | language: PropTypes.string,
33 | stargazers_count: PropTypes.number,
34 | forks_count: PropTypes.number,
35 | html_url: PropTypes.string,
36 | name: PropTypes.string,
37 | description: PropTypes.string,
38 | }),
39 | };
40 | FollowerItem.defaultProps = {
41 | follower: {},
42 | };
43 |
--------------------------------------------------------------------------------
/src/views/Followers.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import FollowerItem from './FollowerItem';
3 | import {getFollowers} from '../services/github-api'
4 | import PropTypes from 'prop-types'
5 |
6 | export default class Followers extends React.Component {
7 | constructor() {
8 | super()
9 | this.state = {followers: []}
10 | }
11 |
12 | getFollowers() {
13 | const {username} = this.props
14 | this.props.getFollowers(username).then(followers => {
15 | this.setState({followers});
16 | });
17 | }
18 |
19 | componentWillMount() {
20 | this.getFollowers();
21 | }
22 |
23 | render() {
24 | const {followers} = this.state
25 | return (
26 |
27 | {renderFollowers(followers)}
28 |
29 | );
30 | }
31 | }
32 |
33 | Followers.propTypes = {
34 | username: PropTypes.string.isRequired,
35 | getFollowers: PropTypes.func,
36 | };
37 | Followers.defaultProps = {getFollowers}
38 |
39 | function renderFollowers(followers) {
40 | console.log(followers);
41 | return followers
42 | .map(follower => );
43 | }
44 |
--------------------------------------------------------------------------------
/src/views/Following.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import FollowingItem from './FollowingItem';
3 | import {getFollowing} from '../services/github-api'
4 | import PropTypes from 'prop-types'
5 |
6 | export default class Following extends React.Component {
7 | constructor() {
8 | super()
9 | this.state = {following: []}
10 | }
11 |
12 | getFollowing() {
13 | const {username} = this.props
14 | this.props.getFollowing(username).then(following => {
15 | this.setState({following});
16 | });
17 | }
18 |
19 | componentWillMount() {
20 | this.getFollowing();
21 | }
22 |
23 | render() {
24 | const {following} = this.state
25 | return (
26 |
27 | {renderFollowing(following)}
28 |
29 | );
30 | }
31 | }
32 |
33 | Following.propTypes = {
34 | username: PropTypes.string.isRequired,
35 | getFollowing: PropTypes.func,
36 | };
37 | Following.defaultProps = {getFollowing}
38 |
39 | function renderFollowing(following) {
40 | return following
41 | .map(followingUser => );
42 | }
43 |
--------------------------------------------------------------------------------
/src/views/FollowingItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default FollowingItem;
5 |
6 | function FollowingItem({following}) {
7 | return (
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 | {following.name}
23 | {following.login}
24 |
25 |
26 | );
27 | }
28 |
29 | FollowingItem.propTypes = {
30 | following: PropTypes.shape({
31 | stargazers_count: PropTypes.number,
32 | forks_count: PropTypes.number,
33 | html_url: PropTypes.string,
34 | name: PropTypes.string,
35 | description: PropTypes.string,
36 | }),
37 | };
38 |
39 | FollowingItem.defaultProps = {
40 | following: {},
41 | };
42 |
--------------------------------------------------------------------------------
/src/views/Github.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import UserProfile from './UserProfile'
3 | import Repositories from './Repositories'
4 | import Stars from './Stars'
5 | import Followers from './Followers'
6 | import Following from './Following'
7 | import RepositoryFilter from './RepositoryFilter'
8 | import PropTypes from 'prop-types';
9 | import {TabView, TabPanel} from 'primereact/components/tabview/TabView';
10 |
11 | export default class Github extends React.Component {
12 | constructor(props) {
13 | super(props)
14 | this.state = {repoFilter: '', starFilter: ''}
15 |
16 | }
17 |
18 | handleRepoFilterUpdate = (repoFilter) => {
19 | this.setState({repoFilter})
20 | }
21 |
22 | handleStarFilterUpdate = (starFilter) => {
23 | this.setState({starFilter})
24 | }
25 |
26 | render() {
27 | const {username} = this.props.match.params
28 | const {repoFilter, starFilter} = this.state
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | );
58 | }
59 | }
60 |
61 | Github.propTypes = {
62 | params: PropTypes.shape({
63 | username: PropTypes.string,
64 | }),
65 | }
66 |
--------------------------------------------------------------------------------
/src/views/Repositories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RepositoryItem from './RepositoryItem';
3 | import {getRepositories} from '../services/github-api'
4 | import PropTypes from 'prop-types'
5 |
6 | export default class Repositories extends React.Component {
7 | constructor() {
8 | super()
9 | this.state = {repositories: []}
10 | }
11 |
12 | getRepositories() {
13 | const {username} = this.props
14 | this.props.getRepositories(username).then(repositories => {
15 | this.setState({repositories});
16 | });
17 | }
18 |
19 | componentWillMount() {
20 | this.getRepositories();
21 | }
22 |
23 | render() {
24 | const {repositories} = this.state
25 | const {filter} = this.props
26 | return (
27 |
28 | {renderRepositories(repositories, filter.toLowerCase())}
29 |
30 | );
31 | }
32 | }
33 |
34 | Repositories.propTypes = {
35 | filter: PropTypes.string.isRequired,
36 | username: PropTypes.string.isRequired,
37 | getRepositories: PropTypes.func,
38 | };
39 | Repositories.defaultProps = {getRepositories}
40 |
41 | function renderRepositories(repositories, filter) {
42 | return repositories
43 | .filter(repository => {
44 | return !filter ||
45 | (repository.name && repository.name.toLowerCase().includes(filter)) ||
46 | (repository.description && repository.description.toLowerCase().includes(filter));
47 | })
48 | .sort((a, b) => Date.parse(b.pushed_at) - Date.parse(a.pushed_at))
49 | .map(repository => );
50 | }
51 |
--------------------------------------------------------------------------------
/src/views/RepositoryFilter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types'
3 | import {InputText} from 'primereact/components/inputtext/InputText';
4 |
5 |
6 | export default class RepositoryFilter extends React.Component {
7 | render() {
8 | return (
9 |
10 | this.props.onUpdate(value)}
14 | />
15 |
16 | );
17 | }
18 | }
19 |
20 | RepositoryFilter.propTypes = {
21 | onUpdate: PropTypes.func.isRequired,
22 | };
23 |
--------------------------------------------------------------------------------
/src/views/RepositoryItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import moment from 'moment';
3 | import PropTypes from 'prop-types';
4 |
5 | export default RepositoryItem;
6 |
7 | function RepositoryItem({repository}) {
8 | const timeUpdated = moment(repository.pushed_at).fromNow();
9 | return (
10 |
11 |
12 | {repository.description}
13 |
14 | {repository.language}
15 | {repository.stargazers_count}
16 | {repository.forks_count}
17 |
18 |
19 |
20 | );
21 | }
22 |
23 | RepositoryItem.propTypes = {
24 | repository: PropTypes.shape({
25 | pushed_at: PropTypes.string,
26 | language: PropTypes.string,
27 | stargazers_count: PropTypes.number,
28 | forks_count: PropTypes.number,
29 | html_url: PropTypes.string,
30 | name: PropTypes.string,
31 | description: PropTypes.string,
32 | }),
33 | };
34 |
35 | RepositoryItem.defaultProps = {
36 | repository: {},
37 | };
38 |
--------------------------------------------------------------------------------
/src/views/Search.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {Card} from "primereact/components/card/Card";
3 | import {Button} from "primereact/components/button/Button";
4 | import {InputText} from "primereact/components/inputtext/InputText";
5 | import {withRouter} from "react-router-dom";
6 | import PropTypes from 'prop-types';
7 |
8 | class Search extends React.Component {
9 | constructor() {
10 | super();
11 | this.state = {
12 | value: ''
13 | };
14 | this.handleClick = this.handleClick.bind(this);
15 | }
16 |
17 | handleClick = (e) => {
18 | e.preventDefault();
19 | this.props.history.push(`/react-github/${this.state.value}`);
20 | }
21 |
22 | render() {
23 |
24 | return (
25 |
26 |
36 | );
37 | }
38 | }
39 |
40 | export default withRouter(Search);
41 |
42 | Search.propTypes = {
43 | params: PropTypes.shape({
44 | username: PropTypes.string,
45 | }),
46 | }
47 |
--------------------------------------------------------------------------------
/src/views/StarItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import moment from 'moment';
3 | import PropTypes from 'prop-types';
4 |
5 | export default StarItem;
6 |
7 | function StarItem({repo}) {
8 | const timeUpdated = moment(repo.pushed_at).fromNow();
9 | return (
10 |
11 |
12 | {repo.description}
13 |
14 | {repo.language}
15 | {repo.stargazers_count}
16 | {repo.forks_count}
17 |
18 |
19 |
20 | );
21 | }
22 |
23 | StarItem.propTypes = {
24 | repo: PropTypes.shape({
25 | pushed_at: PropTypes.string,
26 | language: PropTypes.string,
27 | stargazers_count: PropTypes.number,
28 | forks_count: PropTypes.number,
29 | html_url: PropTypes.string,
30 | name: PropTypes.string,
31 | description: PropTypes.string,
32 | }),
33 | };
34 |
35 | StarItem.defaultProps = {
36 | repo: {},
37 | };
38 |
--------------------------------------------------------------------------------
/src/views/Stars.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import StarItem from './StarItem';
3 | import {getStars} from '../services/github-api'
4 | import PropTypes from 'prop-types'
5 |
6 | export default class Stars extends React.Component {
7 | constructor() {
8 | super()
9 | this.state = {stars: []}
10 | }
11 |
12 | getStars() {
13 | const {username} = this.props
14 | this.props.getStars(username).then(stars => {
15 | this.setState({stars});
16 | });
17 | }
18 |
19 | componentWillMount() {
20 | this.getStars();
21 | }
22 |
23 | render() {
24 | const {stars} = this.state
25 | const {filter} = this.props
26 | return (
27 |
28 | {renderStars(stars, filter.toLowerCase())}
29 |
30 | );
31 | }
32 | }
33 |
34 | Stars.propTypes = {
35 | filter: PropTypes.string.isRequired,
36 | username: PropTypes.string.isRequired,
37 | getStars: PropTypes.func,
38 | };
39 | Stars.defaultProps = {getStars}
40 |
41 | function renderStars(stars, filter) {
42 | return stars
43 | .filter(star => {
44 | return !filter ||
45 | (star.name && star.name.toLowerCase().includes(filter)) ||
46 | (star.description && star.description.toLowerCase().includes(filter));
47 | })
48 | .sort((a, b) => Date.parse(b.pushed_at) - Date.parse(a.pushed_at))
49 | .map(repo => );
50 | }
51 |
--------------------------------------------------------------------------------
/src/views/UserProfile.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {getUserData} from '../services/github-api'
3 | import PropTypes from 'prop-types';
4 | import '../App.css';
5 |
6 | export default class UserProfile extends React.Component {
7 | constructor() {
8 | super()
9 | this.state = {user: {}, orgs: []}
10 | }
11 |
12 | getUser() {
13 | const {username} = this.props
14 | getUserData(username)
15 | .then(({user, orgs}) => {
16 | this.setState({user, orgs});
17 | });
18 | }
19 |
20 | componentWillMount() {
21 | this.getUser();
22 | }
23 |
24 | render() {
25 | const {user, orgs} = this.state;
26 | return (
27 |
28 |
29 |

37 |
38 | {user.name}
39 | {user.login}
40 |
41 |
44 |
45 |
46 |
Organizations
47 | {orgs.map(org => (
48 |

54 | ))}
55 | {/*
*/}
56 |
57 |
58 |
59 | Repositories
60 | {user.public_repos}
61 | Followers
62 | {user.followers}
63 | Following
64 | {user.following}
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | );
75 | }
76 | }
77 |
78 | UserProfile.propTypes = {
79 | username: PropTypes.string.isRequired
80 | }
81 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 |
3 | module.exports = {
4 | entry: `${__dirname}/src/index.js`,
5 | output: {
6 | path: `${__dirname}/build`,
7 | publicPath: '/react-github/build/',
8 | filename: 'bundle.js',
9 | },
10 |
11 | module: {
12 | rules: [
13 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
14 | { test: /\.css$/, loader:['style-loader', 'css-loader']},
15 | {
16 | test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
17 | loader: 'file-loader?name=assets/[name].[hash].[ext]'
18 | }
19 | ],
20 | },
21 |
22 | plugins: process.argv.indexOf('-p') === -1 ? [] : [
23 | new webpack.optimize.UglifyJsPlugin({
24 | output: {
25 | comments: false,
26 | },
27 | }),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------