├── tsuru.yaml ├── __mocks__ ├── file-mock.js └── gatsby.js ├── src ├── components │ ├── Seo │ │ ├── index.js │ │ └── Seo.js │ ├── Loading │ │ ├── index.js │ │ └── Loading.js │ ├── Message │ │ ├── index.js │ │ └── Message.js │ ├── Project │ │ ├── index.js │ │ └── Project.js │ ├── ButtonLink │ │ ├── index.js │ │ └── ButtonLink.js │ ├── TextInput │ │ ├── index.js │ │ └── TextInput.js │ ├── ProjectList │ │ ├── index.js │ │ └── ProjectList.js │ ├── SelectInput │ │ ├── index.js │ │ └── SelectInput.js │ ├── HacktoberFestCall │ │ ├── index.js │ │ ├── HacktoberFestCall.js │ │ ├── UserProgress.js │ │ └── ShippingForm.js │ ├── Button │ │ ├── index.js │ │ └── Button.js │ ├── Layout │ │ ├── index.js │ │ ├── Container.js │ │ ├── Layout.js │ │ ├── GlobalStyle.js │ │ ├── Footer.js │ │ └── Header.js │ └── Dialog │ │ ├── index.js │ │ └── Dialog.js ├── images │ ├── 2020 │ │ ├── girl.png │ │ ├── year.png │ │ ├── astronauta.png │ │ ├── background.png │ │ ├── logo-desktop.png │ │ ├── hacktober-callonly.png │ │ ├── together-by-the-code.png │ │ ├── open-bracket.svg │ │ └── big-bracket.svg │ ├── app-icon.png │ ├── hacktoberfest.png │ ├── hacktoberfest-lg.png │ ├── astrunaut-front-lg.jpg │ ├── astrunaut-front-sm.jpg │ └── icons │ │ ├── expand-less.svg │ │ ├── expand-more.svg │ │ ├── stars.js │ │ ├── issues.js │ │ ├── commits.js │ │ └── prs.js ├── constants │ └── colors.js ├── icons │ ├── MenuBurguer.js │ ├── ArrowDown.js │ ├── Merged.js │ ├── TShirt.js │ ├── PullRequest.js │ └── GloboCom.js ├── pages │ ├── 404.js │ ├── projetos.js │ ├── index.test.js │ ├── coders.js │ ├── hacktoberfest.js │ ├── index.js │ └── rules.js └── services │ ├── github.js │ └── api.js ├── .dockerignore ├── .prettierignore ├── .env.example ├── loadershim.js ├── setup-test-env.js ├── data ├── logos │ ├── husky.png │ ├── clappr.svg │ ├── tsuru.svg │ ├── thumbor.svg │ └── megadraft.svg └── featured-projects.json ├── static └── images │ └── opengraph.png ├── docker └── nginx │ ├── Dockerfile │ └── opensource.conf ├── .prettierrc ├── jest-preprocess.js ├── .editorconfig ├── docker-compose.yml ├── Dockerfile ├── jest.config.js ├── LICENSE ├── api ├── server.js └── db.json ├── .gitignore ├── README-pt-BR.md ├── README.md ├── gatsby-config.js ├── Makefile └── package.json /tsuru.yaml: -------------------------------------------------------------------------------- 1 | healthcheck: 2 | path: / 3 | -------------------------------------------------------------------------------- /__mocks__/file-mock.js: -------------------------------------------------------------------------------- 1 | module.exports = "test-file-stub" 2 | -------------------------------------------------------------------------------- /src/components/Seo/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Seo" 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ./node_modules 2 | ./.cache 3 | ./.public 4 | ./docker -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | public/ 3 | node_modules/ 4 | .cache/ -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | GATSBY_GITHUB_TOKEN= 2 | GATSBY_API_URL=http://localhost:3000 -------------------------------------------------------------------------------- /loadershim.js: -------------------------------------------------------------------------------- 1 | global.___loader = { 2 | enqueue: jest.fn(), 3 | } 4 | -------------------------------------------------------------------------------- /setup-test-env.js: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/extend-expect" 2 | -------------------------------------------------------------------------------- /src/components/Loading/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Loading" 2 | -------------------------------------------------------------------------------- /src/components/Message/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Message" 2 | -------------------------------------------------------------------------------- /src/components/Project/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Project" 2 | -------------------------------------------------------------------------------- /src/components/ButtonLink/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./ButtonLink" 2 | -------------------------------------------------------------------------------- /src/components/TextInput/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./TextInput" 2 | -------------------------------------------------------------------------------- /src/components/ProjectList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./ProjectList" 2 | -------------------------------------------------------------------------------- /src/components/SelectInput/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./SelectInput" 2 | -------------------------------------------------------------------------------- /src/components/HacktoberFestCall/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./HacktoberFestCall" 2 | -------------------------------------------------------------------------------- /data/logos/husky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/data/logos/husky.png -------------------------------------------------------------------------------- /src/images/2020/girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/girl.png -------------------------------------------------------------------------------- /src/images/2020/year.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/year.png -------------------------------------------------------------------------------- /src/images/app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/app-icon.png -------------------------------------------------------------------------------- /src/images/hacktoberfest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/hacktoberfest.png -------------------------------------------------------------------------------- /static/images/opengraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/static/images/opengraph.png -------------------------------------------------------------------------------- /src/components/Button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Button" 2 | export { ButtonWrapper } from "./Button" 3 | -------------------------------------------------------------------------------- /src/images/2020/astronauta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/astronauta.png -------------------------------------------------------------------------------- /src/images/2020/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/background.png -------------------------------------------------------------------------------- /src/images/hacktoberfest-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/hacktoberfest-lg.png -------------------------------------------------------------------------------- /src/constants/colors.js: -------------------------------------------------------------------------------- 1 | export default { 2 | PRIMARY_COLOR: "#ed1846", 3 | PRIMARY_COLOR_DARKER: "#ab1334", 4 | } 5 | -------------------------------------------------------------------------------- /src/images/2020/logo-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/logo-desktop.png -------------------------------------------------------------------------------- /src/images/astrunaut-front-lg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/astrunaut-front-lg.jpg -------------------------------------------------------------------------------- /src/images/astrunaut-front-sm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/astrunaut-front-sm.jpg -------------------------------------------------------------------------------- /docker/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | RUN rm etc/nginx/conf.d/default.conf 4 | COPY opensource.conf etc/nginx/conf.d/ 5 | -------------------------------------------------------------------------------- /src/components/Layout/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Layout" 2 | export { default as Container } from "./Container" 3 | -------------------------------------------------------------------------------- /src/images/2020/hacktober-callonly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/hacktober-callonly.png -------------------------------------------------------------------------------- /src/images/2020/together-by-the-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/globocom/opensource/HEAD/src/images/2020/together-by-the-code.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /src/components/Dialog/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Dialog" 2 | export { DialogTitle, DialogBody, DialogFooter, DialogText } from "./Dialog" 3 | -------------------------------------------------------------------------------- /jest-preprocess.js: -------------------------------------------------------------------------------- 1 | const babelOptions = { 2 | presets: ["babel-preset-gatsby"], 3 | } 4 | module.exports = require("babel-jest").createTransformer(babelOptions) 5 | -------------------------------------------------------------------------------- /src/images/icons/expand-less.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/images/icons/expand-more.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | trim_trailing_whitespace = true 7 | 8 | [Makefile] 9 | indent_style = tab 10 | indent_size = 4 11 | 12 | [Dockerfile] 13 | indent_size = 4 14 | 15 | [opensource.conf] 16 | indent_size = 4 -------------------------------------------------------------------------------- /src/icons/MenuBurguer.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default ({ width = 24, height = 24 }) => ( 4 | 5 | Menu 6 | 7 | 8 | ) 9 | -------------------------------------------------------------------------------- /src/components/Layout/Container.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components" 2 | import media from "styled-media-query" 3 | 4 | const Container = styled.div` 5 | padding: 0 1.5rem; 6 | 7 | ${media.greaterThan("large")` 8 | padding: 0; 9 | margin: 0 auto; 10 | max-width: 75rem; 11 | `} 12 | ` 13 | 14 | export default Container 15 | -------------------------------------------------------------------------------- /src/icons/ArrowDown.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default ({ width = 24, height = 24 }) => ( 4 | 14 | ) 15 | -------------------------------------------------------------------------------- /src/images/icons/stars.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | const stars = home => ( 3 | 4 | 8 | 9 | ) 10 | 11 | export default stars 12 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | fe: 5 | restart: always 6 | build: ./docker/nginx 7 | ports: 8 | - '8080:80' 9 | depends_on: 10 | - web 11 | 12 | web: 13 | restart: always 14 | build: ./ 15 | command: 'yarn develop --host 0.0.0.0' 16 | volumes: 17 | - ./src:/app/src 18 | - ./static:/app/static 19 | ports: 20 | - '8000:8000' 21 | -------------------------------------------------------------------------------- /src/icons/Merged.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default ({ width = 98, height = 70 }) => ( 4 | 11 | 15 | 16 | ) 17 | -------------------------------------------------------------------------------- /docker/nginx/opensource.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | 5 | location / { 6 | proxy_set_header Host $host; 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | proxy_set_header X-Forwarded-Proto $scheme; 10 | proxy_set_header X-Forwarded-Host $host; 11 | proxy_pass http://web:8000; 12 | } 13 | } -------------------------------------------------------------------------------- /src/images/icons/issues.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | const issues = home => ( 3 | 4 | 10 | 11 | ) 12 | 13 | export default issues 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine 2 | 3 | RUN mkdir /app 4 | WORKDIR /app 5 | 6 | RUN apk update && \ 7 | apk add --update fftw-dev gcc g++ make libc6-compat util-linux && \ 8 | apk add --no-cache --repository https://alpine.global.ssl.fastly.net/alpine/edge/community vips-dev vips-tools && \ 9 | rm -rf /var/cache/apk/* 10 | 11 | COPY package.json yarn.lock .env.development gatsby-*.js /app/ 12 | COPY static /app/static 13 | COPY src /app/src 14 | COPY data /app/data 15 | 16 | RUN yarn install 17 | 18 | EXPOSE 8000 19 | 20 | CMD ["yarn", "develop", "-H", "0.0.0.0" ] -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.jsx?$": `/jest-preprocess.js`, 4 | }, 5 | moduleNameMapper: { 6 | ".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": `/__mocks__/file-mock.js`, 7 | }, 8 | testPathIgnorePatterns: [`node_modules`, `.cache`, `public`], 9 | transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`], 10 | globals: { 11 | __PATH_PREFIX__: ``, 12 | }, 13 | testURL: `http://localhost`, 14 | setupFiles: [`/loadershim.js`], 15 | setupFilesAfterEnv: [`/setup-test-env.js`], 16 | } 17 | -------------------------------------------------------------------------------- /__mocks__/gatsby.js: -------------------------------------------------------------------------------- 1 | const React = require("react") 2 | const gatsby = jest.requireActual("gatsby") 3 | module.exports = { 4 | ...gatsby, 5 | graphql: jest.fn(), 6 | Link: jest.fn().mockImplementation( 7 | // these props are invalid for an `a` tag 8 | ({ 9 | activeClassName, 10 | activeStyle, 11 | getProps, 12 | innerRef, 13 | partiallyActive, 14 | ref, 15 | replace, 16 | to, 17 | ...rest 18 | }) => 19 | React.createElement("a", { 20 | ...rest, 21 | href: to, 22 | }) 23 | ), 24 | StaticQuery: jest.fn(), 25 | useStaticQuery: jest.fn(), 26 | } 27 | -------------------------------------------------------------------------------- /src/images/icons/commits.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | const commits = home => ( 3 | 4 | 5 | 12 | 16 | 17 | 18 | ) 19 | 20 | export default commits 21 | -------------------------------------------------------------------------------- /src/icons/TShirt.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default ({ width = 84, height = 70 }) => ( 4 | 11 | 17 | 18 | ) 19 | -------------------------------------------------------------------------------- /src/images/2020/open-bracket.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/Loading/Loading.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { keyframes } from "styled-components" 4 | 5 | const blink = keyframes` 6 | 0% {opacity: 0;} 7 | 25% {opacity: .25;} 8 | 50% {opacity: .5;} 9 | 75% {opacity: .75;} 10 | 100% {opacity: 1;} 11 | ` 12 | 13 | const Root = styled.div` 14 | font-family: Hack, monospace; 15 | font-size: 0.875rem; 16 | 17 | i { 18 | animation: ${blink} 1s linear infinite; 19 | margin-left: 2px; 20 | } 21 | ` 22 | 23 | function Loading({ children }) { 24 | return ( 25 | 26 | {children || "Carregando"} 27 | _ 28 | 29 | ) 30 | } 31 | 32 | Loading.propTypes = { 33 | children: PropTypes.node, 34 | } 35 | 36 | export default Loading 37 | -------------------------------------------------------------------------------- /src/images/2020/big-bracket.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/icons/PullRequest.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default ({ width = 60, height = 76 }) => ( 4 | 5 | 11 | 12 | 18 | 19 | ) 20 | -------------------------------------------------------------------------------- /src/components/ButtonLink/ButtonLink.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled from "styled-components" 4 | 5 | import { ButtonWrapper } from "@components/Button" 6 | 7 | const ButtonLinkWrapper = styled(ButtonWrapper).attrs({ 8 | as: "a", 9 | })`` 10 | 11 | function ButtonLink({ children, href, dark, blank, anchorProps }) { 12 | const elProps = { ...(anchorProps || {}) } 13 | 14 | if (blank) { 15 | elProps.target = "_blank" 16 | elProps.rel = "noopener noreferrer" 17 | } 18 | 19 | return ( 20 | 21 | {children} 22 | 23 | ) 24 | } 25 | 26 | ButtonLink.propTypes = { 27 | children: PropTypes.node.isRequired, 28 | dark: PropTypes.bool, 29 | href: PropTypes.string, 30 | blank: PropTypes.bool, 31 | anchorProps: PropTypes.object, 32 | } 33 | 34 | ButtonLink.defaultProps = { 35 | blank: false, 36 | } 37 | 38 | export default ButtonLink 39 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import styled from "styled-components" 3 | import media from "styled-media-query" 4 | 5 | import Layout, { Container } from "@components/Layout" 6 | 7 | const NotFoundMessage = styled.section` 8 | margin-top: 6rem; 9 | 10 | ${media.greaterThan("medium")` 11 | text-align: center; 12 | `} 13 | 14 | h1 { 15 | font-weight: bold; 16 | font-size: 2rem; 17 | margin-bottom: 3rem; 18 | 19 | ${media.greaterThan("medium")` 20 | font-size: 3rem; 21 | margin-bottom: 5rem; 22 | `} 23 | } 24 | 25 | p { 26 | font-size: 1.2rem; 27 | line-height: 2rem; 28 | 29 | ${media.greaterThan("medium")` 30 | font-size: 2rem; 31 | `} 32 | } 33 | ` 34 | 35 | function NotFoundPage() { 36 | return ( 37 | 38 | 39 | 40 |

Página não econtrada

41 |

Descupe, a página que você tentou acessar não existe.

42 |
43 |
44 |
45 | ) 46 | } 47 | 48 | export default NotFoundPage 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 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 | 23 | -------------------------------------------------------------------------------- /api/server.js: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | const jsonServer = require("json-server") 3 | const bodyParser = require("body-parser") 4 | 5 | const server = jsonServer.create() 6 | const router = jsonServer.router(path.join(__dirname, "db.json")) 7 | const middlewares = jsonServer.defaults() 8 | 9 | server.use(middlewares) 10 | 11 | // server.get("/user", (req, res, next) => { 12 | // if ( 13 | // !req.headers.cookie || 14 | // req.headers.cookie.indexOf("logged_in=yes") === -1 15 | // ) { 16 | // res.sendStatus(401) 17 | // } else { 18 | // next() 19 | // } 20 | // }) 21 | 22 | server.use(bodyParser.text()) 23 | server.post("/subscribe", (req, res, next) => { 24 | const data = JSON.parse(req.body) 25 | const db = router.db 26 | const user = db 27 | .get("user") 28 | .cloneDeep() 29 | .value() 30 | 31 | user.result = { 32 | ...user.result, 33 | ...data, 34 | } 35 | 36 | db.get("user") 37 | .assign(user) 38 | .write() 39 | 40 | res.status(201).jsonp(db.get("user").value()) 41 | }) 42 | 43 | server.use(router) 44 | server.listen(3000, () => { 45 | console.log("Demo api server is running...") 46 | }) 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | .env.development 72 | .env.production 73 | -------------------------------------------------------------------------------- /src/components/ProjectList/ProjectList.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled from "styled-components" 4 | import media from "styled-media-query" 5 | import ButtonLink from "@components/ButtonLink" 6 | 7 | const ProjectListWrapper = styled.section` 8 | display: flex; 9 | flex-direction: column; 10 | 11 | ${media.greaterThan("medium")` 12 | display: grid; 13 | grid-template-columns: repeat(2, 1fr); 14 | grid-gap: 2rem 3rem; 15 | `} 16 | 17 | ${media.greaterThan("large")` 18 | grid-template-columns: repeat(3, 1fr); 19 | `} 20 | ` 21 | 22 | const ProjectListButton = styled.div` 23 | margin: 2.5rem; 24 | display: flex; 25 | align-items: center; 26 | justify-content: center; 27 | ` 28 | 29 | function ProjectList({ children, hasShowAll }) { 30 | return ( 31 | 32 | {children} 33 | {hasShowAll && ( 34 | 35 | Ver todos 36 | 37 | )} 38 | 39 | ) 40 | } 41 | 42 | ProjectList.propTypes = { 43 | children: PropTypes.node.isRequired, 44 | hasShowAll: PropTypes.bool.isRequired, 45 | } 46 | 47 | ProjectList.defaultProps = { 48 | hasShowAll: false, 49 | } 50 | 51 | export default ProjectList 52 | -------------------------------------------------------------------------------- /src/components/Message/Message.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { css } from "styled-components" 4 | 5 | const Root = styled.div` 6 | position: absolute; 7 | top: 20px; 8 | left: 0; 9 | text-align: center; 10 | width: 100%; 11 | ` 12 | 13 | const Container = styled.div` 14 | display: inline-block; 15 | min-width: 300px; 16 | padding: 15px 20px; 17 | border-radius: 5px; 18 | box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 19 | 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 20 | 0px 1px 18px 0px rgba(0, 0, 0, 0.12); 21 | 22 | ${props => 23 | props.variant === "info" && 24 | css` 25 | background-color: #90caf9; 26 | `} 27 | ${props => 28 | props.variant === "success" && 29 | css` 30 | background-color: #43a047; 31 | `} 32 | ${props => 33 | props.variant === "error" && 34 | css` 35 | background-color: #d32f2f; 36 | `}; 37 | ` 38 | 39 | function Message({ children, variant }) { 40 | return ( 41 | 42 | {children} 43 | 44 | ) 45 | } 46 | 47 | Message.propTypes = { 48 | children: PropTypes.node.isRequired, 49 | variant: PropTypes.oneOf(["error", "info", "success"]), 50 | } 51 | 52 | Message.defaultProps = { 53 | variant: "info", 54 | } 55 | 56 | export default Message 57 | -------------------------------------------------------------------------------- /src/components/TextInput/TextInput.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { css } from "styled-components" 4 | import Colors from "@constants/colors" 5 | 6 | const Root = styled.div` 7 | margin-bottom: 20px; 8 | ` 9 | 10 | const Label = styled.label` 11 | font-weight: 700; 12 | margin-bottom: 1rem; 13 | display: inline-block; 14 | ` 15 | 16 | const Input = styled.input` 17 | width: 100%; 18 | border: 2px solid #cfd3d4; 19 | font-family: "Open Sans", sans-serif; 20 | border-radius: 6px; 21 | padding: 16px; 22 | font-size: 1.2rem; 23 | background-color: white; 24 | outline: none; 25 | -webkit-appearance: none; 26 | transition: border-color 0.5s; 27 | 28 | ${props => 29 | props.hasError && 30 | css` 31 | border-color: #d32f2f; 32 | `} 33 | 34 | &:focus, 35 | &:hover { 36 | border-color: ${Colors.PRIMARY_COLOR}; 37 | } 38 | ` 39 | 40 | const ErrorText = styled.span` 41 | font-size: 12px; 42 | margin: 10px 5px 0; 43 | color: #d32f2f; 44 | display: inline-block; 45 | ` 46 | 47 | function TextInput({ label, errorText, ...inputProps }) { 48 | return ( 49 | 50 | {label && } 51 | 52 | {errorText && {errorText}} 53 | 54 | ) 55 | } 56 | 57 | TextInput.propTypes = { 58 | label: PropTypes.string, 59 | errorText: PropTypes.string, 60 | } 61 | 62 | export default TextInput 63 | -------------------------------------------------------------------------------- /README-pt-BR.md: -------------------------------------------------------------------------------- 1 | # Globo Open Source 2 | 3 | Globo open source website [https://opensource.globo.com](http://opensource.globo.com). 4 | 5 | Feito com ❤️ para a comunidade de código aberto. 6 | 7 | ## Desenvolvimento 8 | 9 | Você precisa ter `nodejs` e `yarn` instalados. Verifique o `package.json` `engines` para o intervalos de versões propostas. 10 | 11 | Use os seguintes comandos para configurar e executar o aplicativo: 12 | 13 | ```bash 14 | make setup 15 | make start 16 | ``` 17 | 18 | ## Deploy 19 | 20 | ```bash 21 | make deploy 22 | ``` 23 | 24 | > Este website é hospedado por [Tsuru](https://tsuru.io/). 25 | 26 | ## Setup 27 | 28 | A aplicação usa o [Github GraphQL API v4](https://developer.github.com/v4/) acessar dados de organizações e repositórios da Globo. Para se comunicar com o servidor GraphQL, você precisará de um [OAuth token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) com os seguintes escopos: 29 | 30 | ```txt 31 | user 32 | read:org 33 | ``` 34 | 35 | Com seu token em mãos, você precisará definir o token para a variável de ambiente `GATSBY_GITHUB_TOKEN`. 36 | 37 | ```bash 38 | export GATSBY_GITHUB_TOKEN= 39 | ``` 40 | 41 | ou criar um arquivo `.env.development` com seu env vars: 42 | 43 | ```ini 44 | // .env.development 45 | GATSBY_GITHUB_TOKEN= 46 | ``` 47 | 48 | ## Licença 49 | 50 | Este projeto está licenciado sob a Licença MIT - leia o arquivo [LICENSE.md](LICENSE) para detalhes. 51 | 52 | *Este artigo foi traduzido do [Inglês](README.md) para o [Português (Brasil)](README-pt-BR.md).* 53 | -------------------------------------------------------------------------------- /src/components/Layout/Layout.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled from "styled-components" 4 | import media from "styled-media-query" 5 | 6 | import GlobalStyle from "./GlobalStyle" 7 | import Header from "./Header" 8 | import Footer from "./Footer" 9 | 10 | const Main = styled.main` 11 | background-color: ${props => (props.dark ? "#000" : "transparent")}; 12 | padding: ${props => (props.noPadding ? "0" : "2rem 0")}; 13 | min-height: calc(100vh - 3.75rem - 7rem); 14 | 15 | ${media.greaterThan("large")` 16 | min-height: calc(100vh - 7.625rem - 6.25rem); 17 | `} 18 | ` 19 | 20 | function Layout({ 21 | children, 22 | darkHeader, 23 | darkFooter, 24 | darkBody, 25 | noPadding, 26 | backgroundImage, 27 | backgroundColor, 28 | }) { 29 | return ( 30 | 31 |
37 | 38 |
39 |
40 | {children} 41 |
42 |
43 |
44 |
45 | ) 46 | } 47 | 48 | Layout.propTypes = { 49 | children: PropTypes.node.isRequired, 50 | darkHeader: PropTypes.bool, 51 | darkFooter: PropTypes.bool, 52 | noPadding: PropTypes.bool, 53 | } 54 | 55 | Layout.defaultProps = { 56 | darkHeader: false, 57 | darkFooter: false, 58 | darkBody: false, 59 | noPadding: false, 60 | } 61 | 62 | export default Layout 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Globo Open Source 2 | 3 | Globo open source website [https://opensource.globo.com](http://opensource.globo.com). 4 | 5 | Made with ❤️ to the open source community. 6 | 7 | ## Development 8 | 9 | You need to have `nodejs` and `yarn` installed. Check the `package.json` `engines` prop for versions range. 10 | 11 | Use the following commands to setup and run the application: 12 | 13 | ```bash 14 | make setup 15 | make start 16 | ``` 17 | 18 | ## Deploy 19 | 20 | ```bash 21 | make deploy 22 | ``` 23 | 24 | > This website is hosted by [Tsuru](https://tsuru.io/). 25 | 26 | ## Setup 27 | 28 | The application uses the [Github GraphQL API v4](https://developer.github.com/v4/) to acess data from the Globo organizations and respositories. To communicate with the GraphQL server, you'll need an [OAuth token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) with the following scopes: 29 | 30 | ```txt 31 | user 32 | read:org 33 | ``` 34 | 35 | With your token in hands, you will need to set the token to the environment variable `GATSBY_GITHUB_TOKEN`. 36 | 37 | ```bash 38 | export GATSBY_GITHUB_TOKEN= 39 | ``` 40 | 41 | or by creating a `.env.development` file with your env vars: 42 | 43 | ```ini 44 | // .env.development 45 | GATSBY_GITHUB_TOKEN= 46 | GATSBY_API_URL= 47 | ``` 48 | 49 | or you could just run `make setup-dev` and replace `.env.development` entries with your env vars values. 50 | 51 | ## License 52 | 53 | This project is licensed under the MIT License - read [LICENSE.md](LICENSE) file for details. 54 | 55 | *This article can also be read in [Brazilian Portuguese](README-pt-BR.md).* 56 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: "Globo - Open Source", 4 | description: "Globo - Por que ❤️ Open Source?", 5 | author: "Globo", 6 | url: "https://opensource.globo.com", 7 | images: { 8 | opengraph: { 9 | type: "image/png", 10 | url: "images/opengraph.png", 11 | width: 1200, 12 | height: 630, 13 | }, 14 | }, 15 | }, 16 | plugins: [ 17 | "gatsby-plugin-react-helmet", 18 | "gatsby-plugin-styled-components", 19 | "gatsby-transformer-json", 20 | "gatsby-transformer-sharp", 21 | { 22 | resolve: "gatsby-plugin-alias-imports", 23 | options: { 24 | alias: { 25 | "@components": "src/components", 26 | "@constants": "src/constants", 27 | "@icons": "src/icons", 28 | "@images": "src/images", 29 | "@pages": "src/pages", 30 | "@services": "src/services" 31 | }, 32 | extensions: [ 33 | "js" 34 | ] 35 | } 36 | }, 37 | { 38 | resolve: "gatsby-plugin-manifest", 39 | options: { 40 | name: "Globo - Open Source", 41 | short_name: "Globo OpenSource", 42 | start_url: "/", 43 | background_color: "#1B3556", 44 | theme_color: "#1B3556", 45 | display: "minimal-ui", 46 | icon: "src/images/app-icon.png", 47 | }, 48 | }, 49 | { 50 | resolve: "gatsby-source-filesystem", 51 | options: { 52 | path: "./data/", 53 | }, 54 | }, 55 | { 56 | resolve: "gatsby-plugin-google-analytics", 57 | options: { 58 | trackingId: "UA-35544505-1", 59 | }, 60 | }, 61 | ], 62 | } 63 | -------------------------------------------------------------------------------- /src/components/Button/Button.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { css } from "styled-components" 4 | import media from "styled-media-query" 5 | import Colors from "@constants/colors" 6 | 7 | const ButtonWrapper = styled.button` 8 | height: 56px; 9 | display: inline-flex; 10 | align-items: center; 11 | cursor: pointer; 12 | border-radius: 36px; 13 | border: 2px solid #000; 14 | padding: 1rem 2.3rem; 15 | font-weight: 600; 16 | white-space: nowrap; 17 | outline: 0; 18 | -webkit-appearance: none; 19 | -webkit-tap-highlight-color: transparent; 20 | font-size: inherit; 21 | font-family: inherit; 22 | transition: all 0.5s ease 0s; 23 | 24 | ${props => 25 | props.dark 26 | ? css` 27 | color: #fff; 28 | border-color: ${Colors.PRIMARY_COLOR}; 29 | background-color: ${Colors.PRIMARY_COLOR}; 30 | ` 31 | : css` 32 | color: #fff; 33 | border-color: ${Colors.PRIMARY_COLOR}; 34 | background-color: ${Colors.PRIMARY_COLOR}; 35 | `} 36 | 37 | &:hover { 38 | ${media.greaterThan("large")` 39 | border-color: ${Colors.PRIMARY_COLOR_DARKER}; 40 | background-color: ${Colors.PRIMARY_COLOR_DARKER}; 41 | color: #fff; 42 | `} 43 | } 44 | ` 45 | 46 | function Button({ children, dark, ...buttonProps }) { 47 | return ( 48 | 49 | {children} 50 | 51 | ) 52 | } 53 | 54 | Button.propTypes = { 55 | children: PropTypes.node.isRequired, 56 | dark: PropTypes.bool, 57 | } 58 | 59 | Button.defaultProps = { 60 | dark: false, 61 | } 62 | 63 | export default Button 64 | export { ButtonWrapper } 65 | -------------------------------------------------------------------------------- /src/components/SelectInput/SelectInput.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import styled, { css } from "styled-components" 3 | 4 | import ArrowDownIcon from "@icons/ArrowDown" 5 | import Colors from "@constants/colors" 6 | 7 | const Root = styled.div` 8 | margin-bottom: 20px; 9 | ` 10 | 11 | const Label = styled.label` 12 | font-weight: 700; 13 | margin-bottom: 1rem; 14 | display: inline-block; 15 | ` 16 | 17 | const Select = styled.select` 18 | width: 100%; 19 | border: 2px solid #cfd3d4; 20 | font-family: "Open Sans", sans-serif; 21 | border-radius: 6px; 22 | padding: 16px; 23 | padding-right: 40px; 24 | font-size: 1.2rem; 25 | background-color: white; 26 | outline: none; 27 | -webkit-appearance: none; 28 | transition: border-color 0.5s; 29 | cursor: pointer; 30 | 31 | ${props => 32 | props.hasError && 33 | css` 34 | border-color: #d32f2f; 35 | `} 36 | 37 | &:focus, 38 | &:hover { 39 | border-color: ${Colors.PRIMARY_COLOR}; 40 | } 41 | ` 42 | 43 | const SelectRoot = styled.div` 44 | position: relative; 45 | ` 46 | 47 | const SelectIcon = styled.i` 48 | position: absolute; 49 | top: calc(50% - 16px); 50 | right: 4px; 51 | color: #cfd3d4; 52 | 53 | svg { 54 | width: 36px; 55 | height: 36px; 56 | fill: currentColor; 57 | pointer-events: none; 58 | } 59 | ` 60 | 61 | const ErrorText = styled.span` 62 | font-size: 12px; 63 | margin: 10px 5px 0; 64 | color: #d32f2f; 65 | display: inline-block; 66 | ` 67 | 68 | function SelectInput({ children, label, errorText, ...inputProps }) { 69 | return ( 70 | 71 | {label && } 72 | 73 | 74 | 75 | 76 | 77 | 78 | {errorText && {errorText}} 79 | 80 | ) 81 | } 82 | 83 | export default SelectInput 84 | -------------------------------------------------------------------------------- /src/images/icons/prs.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | const prs = home => ( 3 | 4 | 10 | 11 | ) 12 | 13 | export default prs 14 | -------------------------------------------------------------------------------- /src/components/Dialog/Dialog.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled from "styled-components" 4 | 5 | const Root = styled.div` 6 | top: 0; 7 | left: 0; 8 | right: 0; 9 | bottom: 0; 10 | z-index: 3; 11 | position: fixed; 12 | ` 13 | 14 | const Overlay = styled.div` 15 | top: 0; 16 | left: 0; 17 | right: 0; 18 | bottom: 0; 19 | z-index: -1; 20 | position: fixed; 21 | background-color: rgba(0, 0, 0, 0.6); 22 | ` 23 | 24 | const Container = styled.div` 25 | height: 100%; 26 | display: flex; 27 | align-items: center; 28 | justify-content: center; 29 | ` 30 | 31 | const Content = styled.div` 32 | flex: 1; 33 | max-width: 600px; 34 | max-height: calc(100% - 40px); 35 | background-color: #fff; 36 | text-align: left; 37 | border-radius: 10px; 38 | display: flex; 39 | position: relative; 40 | flex-direction: column; 41 | margin: 10px; 42 | color: #000; 43 | ` 44 | 45 | export const DialogTitle = styled.div` 46 | padding: 30px; 47 | font-weight: 700; 48 | font-size: 1.5rem; 49 | color: #000; 50 | ` 51 | 52 | export const DialogBody = styled.div` 53 | padding: 20px 30px; 54 | overflow-y: auto; 55 | color: #000; 56 | ` 57 | 58 | export const DialogFooter = styled.div` 59 | padding: 20px 30px; 60 | text-align: right; 61 | 62 | * + * { 63 | margin-left: 20px; 64 | } 65 | ` 66 | 67 | export const DialogText = styled.p` 68 | margin-bottom: 2rem; 69 | ` 70 | 71 | function Dialog({ children, open, onClose }) { 72 | if (!open) { 73 | return null 74 | } 75 | 76 | return ( 77 | 78 | 79 | 80 | {children} 81 | 82 | 83 | 84 | ) 85 | } 86 | 87 | Dialog.propTypes = { 88 | children: PropTypes.node.isRequired, 89 | open: PropTypes.bool, 90 | onClose: PropTypes.func, 91 | } 92 | 93 | Dialog.defaultProps = { 94 | open: false, 95 | } 96 | 97 | export default Dialog 98 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NPM ?= $(shell which npm) 2 | YARN ?= $(shell which yarn) 3 | PKG_MANAGER ?= $(if $(YARN),$(YARN),$(NPM)) 4 | 5 | .SILENT: 6 | .DEFAULT_GOAL=help 7 | 8 | COLOR_RESET = \033[0m 9 | COLOR_GREEN = \033[32m 10 | COLOR_YELLOW = \033[33m 11 | 12 | PROJECT_NAME = `basename $(PWD)` 13 | 14 | ## print help 15 | help: 16 | printf "${COLOR_YELLOW}\n${PROJECT_NAME}\n\n${COLOR_RESET}" 17 | awk '/^[a-zA-Z\-\_0-9\.%]+:/ { \ 18 | helpMessage = match(lastLine, /^## (.*)/); \ 19 | if (helpMessage) { \ 20 | helpCommand = substr($$1, 0, index($$1, ":")); \ 21 | helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ 22 | printf "${COLOR_GREEN}$$ make %s${COLOR_RESET} %s\n", helpCommand, helpMessage; \ 23 | } \ 24 | } \ 25 | { lastLine = $$0 }' $(MAKEFILE_LIST) 26 | printf "\n" 27 | 28 | ## install project dependencies 29 | setup: 30 | @${PKG_MANAGER} install 31 | make setup-dev 32 | 33 | ## start development server 34 | start: 35 | @${PKG_MANAGER} run start 36 | 37 | ## SETUP DEV 38 | setup-dev: 39 | export NODE_ENV=development 40 | cp .env.example .env.development 41 | echo "DEV SETUP DONE" 42 | 43 | ## build static files to production 44 | build: 45 | @${PKG_MANAGER} run build 46 | 47 | 48 | build-dev: 49 | @${PKG_MANAGER} run build:dev 50 | 51 | 52 | ## deploy to production 53 | deploy: build 54 | tsuru app-deploy public -a opensource-web 55 | 56 | ## deploy to development 57 | deploy-dev: build-dev 58 | tsuru app-deploy public -a opensource-web-dev 59 | 60 | ## clean docker-compose images 61 | docker-clean: 62 | docker-compose --project-name ${PROJECT_NAME} rm -f 63 | 64 | ## start development with docker-compose 65 | docker-start: docker-clean 66 | docker-compose --project-name ${PROJECT_NAME} up -d --remove-orphans 67 | 68 | ## build docker-compose images 69 | docker-build: docker-clean 70 | docker-compose --project-name ${PROJECT_NAME} pull 71 | docker-compose --project-name ${PROJECT_NAME} build 72 | 73 | ## stop docker-compose 74 | docker-stop: docker-clean 75 | docker-compose --project-name ${PROJECT_NAME} stop 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "globocom-opensource", 3 | "description": "Globo Open Source community website", 4 | "version": "0.1.0", 5 | "author": "globo", 6 | "keywords": [ 7 | "opensource", 8 | "community", 9 | "globocom", 10 | "gcom", 11 | "gatsby" 12 | ], 13 | "private": true, 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/globocom/opensource" 18 | }, 19 | "engines": { 20 | "node": ">= 8.9.0", 21 | "yarn": ">= 1.0.0" 22 | }, 23 | "scripts": { 24 | "build": "gatsby build", 25 | "build:dev": "env-cmd -f .env.development gatsby build", 26 | "develop": "gatsby develop", 27 | "start": "run-p start:api develop", 28 | "start:api": "nodemon ./api/server.js", 29 | "format": "prettier --write '**/*.js'", 30 | "serve": "gatsby serve", 31 | "test": "jest", 32 | "test:watch": "jest --watch" 33 | }, 34 | "husky": { 35 | "hooks": { 36 | "pre-commit": "pretty-quick --staged" 37 | } 38 | }, 39 | "dependencies": { 40 | "formik": "^1.5.8", 41 | "gatsby": "^2.18.10", 42 | "gatsby-plugin-alias-imports": "^1.0.5", 43 | "gatsby-plugin-google-analytics": "^2.1.31", 44 | "gatsby-plugin-manifest": "^2.2.33", 45 | "gatsby-plugin-react-helmet": "^3.1.18", 46 | "gatsby-plugin-sharp": "^2.3.7", 47 | "gatsby-plugin-styled-components": "^3.1.16", 48 | "gatsby-source-filesystem": "^2.1.42", 49 | "gatsby-transformer-json": "^2.2.22", 50 | "gatsby-transformer-sharp": "^2.3.9", 51 | "lodash": "^4.17.20", 52 | "react": "^16.12.0", 53 | "react-dom": "^16.12.0", 54 | "react-helmet": "^5.2.1", 55 | "react-pluralize": "^1.6.3", 56 | "styled-components": "^4.4.0", 57 | "styled-media-query": "^2.1.2", 58 | "yup": "^0.27.0" 59 | }, 60 | "devDependencies": { 61 | "@testing-library/jest-dom": "^4.2.4", 62 | "@testing-library/react": "^9.3.2", 63 | "babel-jest": "^24.9.0", 64 | "babel-preset-gatsby": "^0.2.25", 65 | "body-parser": "^1.19.0", 66 | "env-cmd": "^10.1.0", 67 | "husky": "^3.0.4", 68 | "identity-obj-proxy": "^3.0.0", 69 | "jest": "^24.9.0", 70 | "json-server": "^0.15.1", 71 | "nodemon": "^1.19.4", 72 | "npm-run-all": "^4.1.5", 73 | "prettier": "^1.18.2", 74 | "pretty-quick": "^1.11.1" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/pages/projetos.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react" 2 | import styled from "styled-components" 3 | 4 | import Seo from "@components/Seo" 5 | import Layout, { Container } from "@components/Layout" 6 | import ProjectList from "@components/ProjectList" 7 | import Project from "@components/Project" 8 | import Loading from "@components/Loading" 9 | 10 | import { getProjects } from "@services/api" 11 | 12 | const Divider = styled.div` 13 | height: 1px; 14 | width: 100%; 15 | background-color: #ddd; 16 | margin: 1rem 0 2rem; 17 | ` 18 | 19 | const ProjectsLoading = styled.div` 20 | padding-top: 2rem; 21 | display: flex; 22 | justify-content: center; 23 | height: 400px; 24 | ` 25 | 26 | function ProjectsPage() { 27 | const [projects, setProjects] = useState([]) 28 | const [isLoading, setIsLoading] = useState(false) 29 | 30 | useEffect(() => { 31 | async function fetchProjects() { 32 | getProjects().then(projects => { 33 | setProjects(projects) 34 | setIsLoading(false) 35 | }) 36 | } 37 | fetchProjects() 38 | }, []) 39 | 40 | return ( 41 | 42 | 46 | 47 | 48 | {projects 49 | .filter(project => project.featured) 50 | .filter(Boolean) 51 | .map((project, i) => ( 52 | 58 | ))} 59 | 60 | 61 | 62 | 63 | {isLoading ? ( 64 | 65 | carregando projetos 66 | 67 | ) : ( 68 | 69 | {projects 70 | .filter(project => !project.featured) 71 | .filter(Boolean) 72 | .map((project, i) => ( 73 | 74 | ))} 75 | 76 | )} 77 | 78 | 79 | ) 80 | } 81 | 82 | export default ProjectsPage 83 | -------------------------------------------------------------------------------- /data/logos/clappr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/logos/tsuru.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/components/Layout/GlobalStyle.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from "styled-components" 2 | import media from "styled-media-query" 3 | import Colors from "@constants/colors" 4 | 5 | const GlobalStyle = createGlobalStyle` 6 | /* http://meyerweb.com/eric/tools/css/reset/ 7 | v2.0 | 20110126 8 | License: none (public domain) 9 | */ 10 | html, body, div, span, applet, object, iframe, 11 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 12 | a, abbr, acronym, address, big, cite, code, 13 | del, dfn, em, img, ins, kbd, q, s, samp, 14 | small, strike, strong, sub, sup, tt, var, 15 | b, u, i, center, 16 | dl, dt, dd, ol, ul, li, 17 | fieldset, form, label, legend, 18 | table, caption, tbody, tfoot, thead, tr, th, td, 19 | article, aside, canvas, details, embed, 20 | figure, figcaption, footer, header, hgroup, 21 | menu, nav, output, ruby, section, summary, 22 | time, mark, audio, video { 23 | margin: 0; 24 | padding: 0; 25 | border: 0; 26 | font-size: 100%; 27 | font: inherit; 28 | vertical-align: baseline; 29 | } 30 | /* HTML5 display-role reset for older browsers */ 31 | article, aside, details, figcaption, figure, 32 | footer, header, hgroup, menu, nav, section { 33 | display: block; 34 | } 35 | body { 36 | line-height: 1; 37 | } 38 | ol, ul { 39 | list-style: none; 40 | } 41 | blockquote, q { 42 | quotes: none; 43 | } 44 | blockquote:before, blockquote:after, 45 | q:before, q:after { 46 | content: ''; 47 | content: none; 48 | } 49 | table { 50 | border-collapse: collapse; 51 | border-spacing: 0; 52 | } 53 | 54 | /* Website */ 55 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&display=swap'); 56 | @import url('https://fonts.googleapis.com/css?family=Bigelow+Rules&display=swap'); 57 | @import url('https://cdn.jsdelivr.net/npm/hack-font@3/build/web/hack-subset.css'); 58 | 59 | html { 60 | box-sizing: border-box; 61 | -webkit-font-smoothing: antialiased; 62 | -moz-osx-font-smoothing: grayscale; 63 | } 64 | 65 | body { 66 | font-family: 'Open Sans', sans-serif; 67 | font-size: 1rem; 68 | color: #000000; 69 | } 70 | 71 | *, *::before, *::after { 72 | box-sizing: inherit; 73 | } 74 | 75 | a { 76 | text-decoration: none; 77 | color: #000000; 78 | transition: all 0.5s ease 0s; 79 | 80 | &:hover { 81 | ${media.greaterThan("large")` 82 | color: ${Colors.PRIMARY_COLOR}; 83 | `} 84 | } 85 | } 86 | ` 87 | 88 | export default GlobalStyle 89 | -------------------------------------------------------------------------------- /src/pages/index.test.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import * as Gatsby from "gatsby" 3 | import { render } from "@testing-library/react" 4 | import * as github from "../services/github" 5 | import IndexPage from "./index" 6 | 7 | jest.mock("../services/github") 8 | 9 | describe("IndexPage", () => { 10 | it("renders correctly", () => { 11 | github.getRepoStats.mockResolvedValue = { 12 | repository: { 13 | object: { history: { totalCount: 10 } }, 14 | issues: { totalCount: 2 }, 15 | pullRequests: { totalCount: 1 }, 16 | stargazers: { totalCount: 32 }, 17 | }, 18 | } 19 | 20 | const useStaticQuery = jest.spyOn(Gatsby, "useStaticQuery") 21 | useStaticQuery 22 | .mockImplementationOnce(() => ({ 23 | allFeaturedProjectsJson: { 24 | edges: [ 25 | { 26 | node: { 27 | id: "2aab3fe4-1e52-5156-8e41-fe236f1dc8c2", 28 | name: "Project", 29 | slug: "project", 30 | owner: "globocom", 31 | repoURL: "https://github.com/globocom/project", 32 | siteURL: "http://project.io", 33 | docsURL: "http://project.io/docs", 34 | description: "This is a nice a really nice project.", 35 | shortDescription: "This is a nice project.", 36 | image: { 37 | publicURL: "/static/project.svg", 38 | }, 39 | }, 40 | }, 41 | ], 42 | }, 43 | })) 44 | .mockImplementationOnce(() => ({ 45 | site: { 46 | siteMetadata: { 47 | title: "Globo - Open Source", 48 | description: "Globo - Por que ❤️ Open Source?", 49 | author: "Globo", 50 | url: "https://opensource.globo.com", 51 | images: { 52 | opengraph: { 53 | type: "image/png", 54 | url: "images/opengraph.png", 55 | width: 1200, 56 | height: 630, 57 | }, 58 | }, 59 | }, 60 | }, 61 | })) 62 | 63 | const { getByTestId } = render() 64 | 65 | expect(useStaticQuery).toHaveBeenCalledTimes(2) 66 | expect(github.getRepoStats).toHaveBeenCalledTimes(1) 67 | 68 | // Header is in dark mode 69 | expect(getByTestId("header")).toHaveStyle("background-color: #000") 70 | 71 | expect(getByTestId("hero-text")).toHaveTextContent( 72 | "Addicted Developersunidos pelo código_" 73 | ) 74 | }) 75 | }) 76 | -------------------------------------------------------------------------------- /src/components/Layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import styled from "styled-components" 4 | import media from "styled-media-query" 5 | 6 | import Container from "./Container" 7 | 8 | const FooterWrapper = styled.footer` 9 | height: 7rem; 10 | background-color: ${props => (props.dark ? "unset" : "")}; 11 | color: ${props => (props.dark ? "#ffffff" : "#000000")}; 12 | 13 | ${media.greaterThan("large")` 14 | height: 6.25rem; 15 | `} 16 | ` 17 | 18 | const FooterContainer = styled(Container)` 19 | height: 100%; 20 | display: flex; 21 | flex-direction: column; 22 | justify-content: flex-start; 23 | 24 | ${media.greaterThan("large")` 25 | flex-direction: row; 26 | justify-content: space-between; 27 | align-items: center; 28 | `} 29 | ` 30 | 31 | const FooterLinks = styled.nav` 32 | padding: 1.5rem 0; 33 | 34 | ul { 35 | width: 100%; 36 | display: flex; 37 | align-items: center; 38 | 39 | ${media.greaterThan("large")` 40 | width: auto; 41 | `} 42 | } 43 | 44 | li { 45 | color: ${props => (props.dark ? "#ffffff" : "#000000")}; 46 | } 47 | 48 | li + li { 49 | margin-left: 2.125rem; 50 | 51 | ${media.greaterThan("large")` 52 | margin-left: 2.5rem; 53 | `} 54 | } 55 | ` 56 | 57 | const FooterLinkWrapper = styled.a` 58 | font-weight: bold; 59 | color: inherit; 60 | ` 61 | 62 | const FooterRights = styled.div` 63 | width: 100%; 64 | ${media.greaterThan("large")` 65 | width: auto; 66 | `} 67 | ` 68 | 69 | function FooterLink({ children, href }) { 70 | return ( 71 | 72 | {children} 73 | 74 | ) 75 | } 76 | 77 | const currentYear = new Date().getFullYear() 78 | 79 | function Footer({ dark }) { 80 | return ( 81 | 82 | 83 | 84 |
    85 |
  • 86 | 87 | GitHub 88 | 89 |
  • 90 |
  • 91 | Blog 92 |
  • 93 |
  • 94 | 95 | Trabalhe conosco 96 | 97 |
  • 98 |
99 |
100 | © {currentYear} globo 101 |
102 |
103 | ) 104 | } 105 | 106 | Footer.propTypes = { 107 | dark: PropTypes.bool, 108 | } 109 | 110 | export default Footer 111 | -------------------------------------------------------------------------------- /src/icons/GloboCom.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default ({ width = 24, height = 24 }) => ( 4 | 5 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /data/featured-projects.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Megadraft", 4 | "owner": "globocom", 5 | "slug": "megadraft", 6 | "image": "logos/megadraft.svg", 7 | "repoURL": "https://github.com/globocom/megadraft", 8 | "siteURL": "http://megadraft.io", 9 | "docsURL": "http://megadraft.io/#/docs/overview", 10 | "shortDescription": "Megadraft is a Rich Text editor built on top of Facebook's Draft.JS featuring a nice default base of components and extensibility." 11 | }, 12 | { 13 | "name": "Tsuru", 14 | "slug": "tsuru", 15 | "owner": "tsuru", 16 | "image": "logos/tsuru.svg", 17 | "repoURL": "https://github.com/tsuru/tsuru", 18 | "siteURL": "http://tsuru.io", 19 | "docsURL": "https://docs.tsuru.io", 20 | "shortDescription": "Open source, extensible and Docker-based Platform as a Service (PaaS).", 21 | "description": "Tsuru is an extensible and open source Platform as a Service (PaaS) that makes application deployments faster and easier. With tsuru, you don’t need to think about servers at all. As an application developer, you can: Back apps with add-on resources such as SQL and NoSQL databases Manage apps using the tsuru command-line tool Deploy apps using Git, tsuru app-deploy or using docker images directly." 22 | }, 23 | { 24 | "name": "Thumbor", 25 | "slug": "thumbor", 26 | "owner": "thumbor", 27 | "image": "logos/thumbor.svg", 28 | "repoURL": "https://github.com/thumbor/thumbor", 29 | "siteURL": "http://thumbor.org", 30 | "docsURL": "https://thumbor.readthedocs.io", 31 | "shortDescription": "Thumbor is an open-source photo thumbnail service by globo.", 32 | "description": "Thumbor is a smart imaging service. It enables on-demand crop, resizing and flipping of images. It features a very smart detection of important points in the image for better cropping and resizing, using state-of-the-art face and feature detection algorithms (more on that in Detection Algorithms). Save time and money in your company with Thumbor." 33 | }, 34 | { 35 | "name": "Clappr", 36 | "slug": "clappr", 37 | "owner": "clappr", 38 | "image": "logos/clappr.svg", 39 | "repoURL": "https://github.com/clappr/clappr", 40 | "siteURL": "http://clappr.github.io", 41 | "docsURL": "http://clappr.github.io", 42 | "shortDescription": "An extensible media player for the web.", 43 | "description": "🎬 An extensible media player for the web." 44 | }, 45 | { 46 | "name": "huskyCI", 47 | "slug": "huskyci", 48 | "owner": "globocom", 49 | "image": "logos/husky.png", 50 | "repoURL": "https://github.com/globocom/huskyCI", 51 | "siteURL": "https://github.com/globocom/huskyCI", 52 | "docsURL": "https://github.com/globocom/huskyCI/wiki", 53 | "shortDescription": "Performing security tests inside your CI.", 54 | "description": "huskyCI is an open-source tool that performs security tests inside CI pipelines of multiple projects and centralizes all results into a database for further analysis and metrics." 55 | } 56 | ] -------------------------------------------------------------------------------- /src/components/Seo/Seo.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | import Helmet from "react-helmet" 4 | 5 | import { useStaticQuery, graphql } from "gatsby" 6 | 7 | function Seo({ lang, title, description, keywords, meta }) { 8 | const data = useStaticQuery(graphql` 9 | query SeoQuery { 10 | site { 11 | siteMetadata { 12 | title 13 | description 14 | author 15 | url 16 | images { 17 | opengraph { 18 | type 19 | url 20 | width 21 | height 22 | } 23 | } 24 | } 25 | } 26 | } 27 | `) 28 | 29 | const { siteMetadata } = data.site 30 | const metaTitle = title 31 | ? `${title} | ${siteMetadata.title}` 32 | : siteMetadata.title 33 | 34 | const metaDescription = description || siteMetadata.description 35 | 36 | const { 37 | images: { opengraph: metaImg }, 38 | } = siteMetadata 39 | 40 | const metaTags = [ 41 | { 42 | name: `description`, 43 | content: metaDescription, 44 | }, 45 | { 46 | name: `keywords`, 47 | content: keywords.join(`, `), 48 | }, 49 | { 50 | name: `author`, 51 | content: siteMetadata.author, 52 | }, 53 | { 54 | property: `og:type`, 55 | content: `website`, 56 | }, 57 | { 58 | property: `og:title`, 59 | content: metaTitle, 60 | }, 61 | { 62 | property: `og:description`, 63 | content: metaDescription, 64 | }, 65 | { 66 | property: `og:image`, 67 | content: `${siteMetadata.url}/${metaImg.url}`, 68 | }, 69 | { 70 | property: `og:image:type`, 71 | content: metaImg.type, 72 | }, 73 | { 74 | property: `og:image:width`, 75 | content: metaImg.width, 76 | }, 77 | { 78 | property: `og:image:height`, 79 | content: metaImg.height, 80 | }, 81 | { 82 | name: `twitter:card`, 83 | content: `summary_large_image`, 84 | }, 85 | { 86 | name: `twitter:site`, 87 | content: `@globocom`, 88 | }, 89 | { 90 | name: `twitter:title`, 91 | content: metaTitle, 92 | }, 93 | { 94 | name: `twitter:description`, 95 | content: metaDescription, 96 | }, 97 | { 98 | name: `twitter:image`, 99 | content: `${siteMetadata.url}/${metaImg.url}`, 100 | }, 101 | ].concat(meta) 102 | 103 | return 104 | } 105 | 106 | Seo.propTypes = { 107 | lang: PropTypes.string, 108 | title: PropTypes.string, 109 | description: PropTypes.string, 110 | keywords: PropTypes.arrayOf(PropTypes.string), 111 | meta: PropTypes.array, 112 | } 113 | 114 | Seo.defaultProps = { 115 | lang: "pt-br", 116 | meta: [], 117 | keywords: ["opensource", "community", "globocom", "gcom"], 118 | } 119 | 120 | export default Seo 121 | -------------------------------------------------------------------------------- /src/services/github.js: -------------------------------------------------------------------------------- 1 | const GITHUB_TOKEN = process.env.GATSBY_GITHUB_TOKEN 2 | 3 | const ORGS = [ 4 | { login: "clappr", stars: 30 }, 5 | { login: "fastlane-queue", stars: 10 }, 6 | { login: "galeb", stars: 10 }, 7 | { login: "globocom", stars: 30 }, 8 | { login: "thumbor", stars: 30 }, 9 | { login: "tsuru", stars: 30 }, 10 | ] 11 | 12 | const ORG_LOGINS = ORGS.map(org => org.login) 13 | 14 | const githubClient = async (query, variables = {}) => { 15 | let resp 16 | 17 | try { 18 | resp = await fetch("https://api.github.com/graphql", { 19 | method: "POST", 20 | body: JSON.stringify({ query, variables }), 21 | headers: { 22 | Authorization: `Bearer ${GITHUB_TOKEN}`, 23 | }, 24 | }) 25 | } catch (error) { 26 | console.error("[GITHUB] Fail to fetch", error) 27 | } 28 | 29 | if (resp.status !== 200) { 30 | console.error(`[GITHUB] Fail to fetch. Status: ${resp.status}`) 31 | return null 32 | } 33 | 34 | const data = await resp.json() 35 | return data.data 36 | } 37 | 38 | const getUserProgress = async login => { 39 | const query = ` 40 | query GetUserProgress($login: String!) { 41 | user(login: $login) { 42 | avatarUrl 43 | pullRequests( 44 | first: 100, 45 | states: [OPEN, MERGED], 46 | orderBy: { field: CREATED_AT, direction: DESC } 47 | ) { 48 | nodes { 49 | title 50 | createdAt 51 | closed 52 | merged 53 | mergedAt 54 | state 55 | repository { 56 | name 57 | owner { 58 | login 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | ` 66 | 67 | const data = await githubClient(query, { 68 | login, 69 | }) 70 | 71 | if (data) { 72 | const { pullRequests, ...user } = data.user 73 | const stats = { ...user, merged: 0, opened: 0 } 74 | 75 | pullRequests.nodes 76 | .filter(pr => { 77 | const currentYear = new Date().getFullYear() 78 | const startDate = new Date(currentYear, 9, 1, 0, 0) 79 | const endDate = new Date(currentYear, 10, 1, 0, 0) 80 | 81 | const createdAt = new Date(pr.createdAt) 82 | const targetOrg = pr.repository.owner.login 83 | return ( 84 | createdAt >= startDate && 85 | createdAt <= endDate && 86 | ORG_LOGINS.includes(targetOrg) 87 | ) 88 | }) 89 | .forEach(pr => { 90 | if (pr.state === "MERGED") { 91 | stats.merged += 1 92 | stats.opened += 1 93 | } 94 | if (pr.state === "OPEN") { 95 | stats.opened += 1 96 | } 97 | }) 98 | 99 | return stats 100 | } 101 | } 102 | 103 | const getIssuesUrl = () => { 104 | const url = new URL("https://github.com/search") 105 | const query = ["label:hacktoberfest", "state:open", "type:issue"] 106 | 107 | ORG_LOGINS.forEach(login => { 108 | query.push(`user:${login}`) 109 | }) 110 | url.searchParams.append("q", query.join(" ")) 111 | 112 | return url.toString() 113 | } 114 | 115 | export { getUserProgress, getIssuesUrl } 116 | -------------------------------------------------------------------------------- /src/services/api.js: -------------------------------------------------------------------------------- 1 | import get from "lodash/get" 2 | 3 | const apiUrl = process.env.GATSBY_API_URL || "http://localhost:3000" 4 | 5 | async function getUser() { 6 | let resp 7 | try { 8 | resp = await fetch(`${apiUrl}/user`, { 9 | credentials: "include", 10 | }) 11 | } catch (error) { 12 | console.error(`[API_ERROR] Fail to fetch user`, error) 13 | return null 14 | } 15 | 16 | if (resp.status !== 200) { 17 | return null 18 | } 19 | 20 | let user 21 | try { 22 | const data = await resp.json() 23 | user = data.result 24 | } catch (error) { 25 | console.error(`[API_ERROR] Invalid response format`, error) 26 | return null 27 | } 28 | 29 | return user 30 | } 31 | 32 | async function updateUser(user) { 33 | let resp 34 | 35 | try { 36 | resp = await fetch(`${apiUrl}/subscribe`, { 37 | method: "POST", 38 | body: JSON.stringify(user), 39 | credentials: "include", 40 | }) 41 | } catch (error) { 42 | console.error("[OPENSOURCE] Fail to save user data", error) 43 | return null 44 | } 45 | 46 | if (resp.status !== 201) { 47 | return null 48 | } 49 | 50 | const data = await resp.json() 51 | return data.result 52 | } 53 | 54 | async function getEdition() { 55 | let resp 56 | 57 | try { 58 | resp = await fetch(`${apiUrl}/edition`) 59 | } catch (error) { 60 | console.error("[OPENSOURCE] Fail to fetch edition", error) 61 | return null 62 | } 63 | 64 | if (resp.status !== 200) { 65 | return null 66 | } 67 | 68 | const data = await resp.json() 69 | return data.result 70 | } 71 | 72 | async function getCoders() { 73 | let resp 74 | 75 | try { 76 | resp = await fetch(`${apiUrl}/status`) 77 | } catch (error) { 78 | console.error("[OPENSOURCE] Fail to fetch coders", error) 79 | return null 80 | } 81 | 82 | if (resp.status !== 200) { 83 | return null 84 | } 85 | 86 | const data = await resp.json() 87 | return data.result 88 | } 89 | 90 | async function haveOpenEdition() { 91 | try { 92 | //const resp = await fetch(`${apiUrl}/haveOpenEdition`) 93 | //const data = await resp.json() 94 | return true 95 | } catch (error) { 96 | return false 97 | } 98 | 99 | return false 100 | } 101 | 102 | async function getProjects() { 103 | let resp 104 | 105 | try { 106 | resp = await fetch(`${apiUrl}/projects`) 107 | } catch (error) { 108 | console.error("[OPENSOURCE] Fail to fetch projects", error) 109 | return null 110 | } 111 | 112 | if (resp.status !== 200) { 113 | return null 114 | } 115 | 116 | const projects = await resp.json() 117 | const data = 118 | (projects.result.items || []).map((project, index) => { 119 | const imageUrl = 120 | typeof project.imageUrl == "object" 121 | ? project.imageUrl.thumborUrl 122 | : project.imageUrl 123 | 124 | let base = { 125 | id: index, 126 | name: project.name, 127 | shortDescription: project.description, 128 | featured: project.featured, 129 | repoURL: project.repositoryUrl, 130 | siteURL: project.website, 131 | docsURL: project.documentationUrl, 132 | image: { 133 | publicURL: imageUrl, 134 | }, 135 | } 136 | if (project.featured) { 137 | base.repoNumbers = { 138 | stars: get(project, "stats.repository.stars.totalCount", 0), 139 | prs: get(project, "stats.repository.pullRequests.totalCount", 0), 140 | issues: get(project, "stats.repository.issues.totalCount", 0), 141 | commits: get( 142 | project, 143 | "stats.repository.object.commit.history.totalCount", 144 | 0 145 | ), 146 | } 147 | } 148 | return base 149 | }) || [] 150 | return data 151 | } 152 | 153 | export { 154 | getUser, 155 | updateUser, 156 | getCoders, 157 | getEdition, 158 | getProjects, 159 | haveOpenEdition, 160 | } 161 | -------------------------------------------------------------------------------- /src/pages/coders.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react" 2 | import styled, { css } from "styled-components" 3 | import Pluralize from "react-pluralize" 4 | 5 | import Seo from "@components/Seo" 6 | import Layout, { Container } from "@components/Layout" 7 | import MergedIcon from "@icons/Merged" 8 | 9 | import { getCoders } from "@services/api" 10 | 11 | const Coders = styled.section` 12 | display: flex; 13 | flex-wrap: wrap; 14 | justify-content: center; 15 | ` 16 | 17 | const CoderRoot = styled.div` 18 | width: 200px; 19 | height: 200px; 20 | margin: 20px; 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | position: relative; 25 | 26 | img { 27 | padding: 2px; 28 | display: block; 29 | border-radius: 10px; 30 | width: 140px; 31 | height: 140px; 32 | box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2); 33 | 34 | ${props => 35 | props.approved && 36 | css` 37 | width: 100%; 38 | height: 100%; 39 | `} 40 | } 41 | ` 42 | 43 | const CoderDetails = styled.div` 44 | position: absolute; 45 | top: 0; 46 | left: 0; 47 | width: 100%; 48 | height: 100%; 49 | display: flex; 50 | flex-direction: column; 51 | align-items: center; 52 | justify-content: center; 53 | color: white; 54 | border-radius: 10px; 55 | background-color: rgba(0, 0, 0, 0.6); 56 | ` 57 | 58 | const CoderText = styled.div` 59 | font-size: 0.8rem; 60 | z-index: 2; 61 | position: absolute; 62 | bottom: 0; 63 | right: 0; 64 | text-align: right; 65 | padding: 20px; 66 | ` 67 | 68 | const CoderName = styled.div` 69 | font-weight: bold; 70 | font-size: 1rem; 71 | margin-bottom: 5px; 72 | ` 73 | 74 | const CoderApproved = styled.div` 75 | margin-top: 5px; 76 | ` 77 | 78 | function Coder({ githubUser, avatar, approved, totalContributions }) { 79 | const [showDetails, setShowDetails] = useState(false) 80 | 81 | function handleShowDetails() { 82 | setShowDetails(true) 83 | } 84 | 85 | function handleHideDetails() { 86 | setShowDetails(false) 87 | } 88 | 89 | return ( 90 | 96 | {githubUser} 101 | {showDetails && ( 102 | 103 | 104 | @{githubUser} 105 | 111 | {approved && ( 112 | 113 | desafio completo 114 | 115 | )} 116 | 117 | 118 | )} 119 | 120 | ) 121 | } 122 | 123 | function CodersPage() { 124 | const [coders, setCoders] = useState([]) 125 | 126 | useEffect(() => { 127 | async function fetchCoders() { 128 | const coders = await getCoders() 129 | setCoders(coders || []) 130 | } 131 | fetchCoders() 132 | }, []) 133 | 134 | return ( 135 | 136 | 140 | 141 | 142 | {coders.map(coder => { 143 | return ( 144 | 151 | ) 152 | })} 153 | 154 | 155 | 156 | ) 157 | } 158 | 159 | export default CodersPage 160 | -------------------------------------------------------------------------------- /data/logos/thumbor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pages/hacktoberfest.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react" 2 | import styled from "styled-components" 3 | import media from "styled-media-query" 4 | 5 | import Seo from "@components/Seo" 6 | import Layout, { Container } from "@components/Layout" 7 | import HacktoberFestCall from "@components/HacktoberFestCall" 8 | import ButtonLink from "@components/ButtonLink" 9 | 10 | import PullRequestIcon from "@icons/PullRequest" 11 | import MergedIcon from "@icons/Merged" 12 | import TShirtIcon from "@icons/TShirt" 13 | 14 | import { getUser } from "@services/api" 15 | import { getIssuesUrl } from "@services/github" 16 | 17 | import BGImage from "@images/2020/background.png" 18 | 19 | const issuesUrl = getIssuesUrl() 20 | 21 | const BGColor = "#201c24" 22 | 23 | const Rules = styled.section` 24 | display: flex; 25 | flex-direction: column; 26 | color: #cfd3d4; 27 | 28 | ${media.greaterThan("medium")` 29 | display: grid; 30 | grid-template-columns: repeat(3, 1fr); 31 | `} 32 | ` 33 | 34 | const Rule = styled.div` 35 | display: flex; 36 | align-items: center; 37 | justify-content: baseline; 38 | flex-direction: column; 39 | margin-bottom: 6rem; 40 | ` 41 | 42 | const RuleIcon = styled.div` 43 | display: flex; 44 | align-items: center; 45 | font-weight: 600; 46 | font-size: 3.75rem; 47 | margin-bottom: 2.5rem; 48 | 49 | span { 50 | margin-right: 1.2rem; 51 | } 52 | ` 53 | 54 | const RuleText = styled.div` 55 | text-align: center; 56 | line-height: 1.75rem; 57 | 58 | strong { 59 | font-weight: 700; 60 | } 61 | ` 62 | 63 | const Projects = styled.section` 64 | padding-top: 5rem; 65 | padding-bottom: 5rem; 66 | color: #fff; 67 | text-align: center; 68 | ` 69 | 70 | const ProjectsTitle = styled.div` 71 | font-weight: bolder; 72 | font-size: 2.25rem; 73 | 74 | ${media.greaterThan("medium")` 75 | font-size: 4rem; 76 | `} 77 | ` 78 | 79 | const ProjectsText = styled.div` 80 | text-align: center; 81 | line-height: 1.75rem; 82 | padding: 2.5rem 0; 83 | 84 | strong { 85 | font-weight: 700; 86 | } 87 | ` 88 | 89 | function HacktoberFestPage() { 90 | const [user, setUser] = useState() 91 | 92 | useEffect(() => { 93 | async function fetchUser() { 94 | const user = await getUser() 95 | setUser(user) 96 | } 97 | fetchUser() 98 | }, []) 99 | 100 | return ( 101 | 108 | 112 | 113 | 114 | 115 | 116 | 117 | 2 118 | 119 | 120 | 121 | Contribua com dois pull requests 122 |
em qualquer projeto Open Source 123 |
da Globo durante o
mês de outubro. 124 |
125 |
126 | 127 | 128 | 129 | 130 | 131 | Garanta que pelo menos um 132 |
pull request seja ACEITO. 133 |
134 |
135 | 136 | 137 | 138 | 139 | 140 | Os 100 primeiros inscritos, 141 |
que completarem os requisitos mínimos, 142 |
ganharão uma camiseta exclusiva a ser 143 |
entregue dentro do território brasileiro. 144 |
145 |
146 |
147 |
148 | 149 | 150 | Projetos 151 | 152 | Pull requests podem ser feitos em qualquer projeto{" "} 153 | da Globo 154 | 155 | 156 | Ver issues 157 | 158 | 159 | 160 |
161 | ) 162 | } 163 | 164 | export default HacktoberFestPage 165 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react" 2 | import styled, { keyframes } from "styled-components" 3 | import media from "styled-media-query" 4 | import { useStaticQuery, graphql } from "gatsby" 5 | 6 | import Seo from "@components/Seo" 7 | import Layout, { Container } from "@components/Layout" 8 | import ProjectList from "@components/ProjectList" 9 | import Project from "@components/Project" 10 | import HacktoberFestCall from "@components/HacktoberFestCall" 11 | import Colors from "@constants/colors" 12 | 13 | import ByTheCodeImage from "@images/2020/together-by-the-code.png" 14 | import BGImage from "@images/2020/background.png" 15 | import GirlImage from "@images/2020/girl.png" 16 | 17 | import get from "lodash/get" 18 | import { getProjects } from "@services/api" 19 | 20 | const blink = keyframes` 21 | 0% {opacity: 0;} 22 | 25% {opacity: .25;} 23 | 50% {opacity: .5;} 24 | 75% {opacity: .75;} 25 | 100% {opacity: 1;} 26 | ` 27 | 28 | const HeroWrapper = styled.div` 29 | color: #fff; 30 | padding-top: 2.3rem; 31 | background-repeat: no-repeat; 32 | background-size: contain; 33 | background-position: bottom center; 34 | display: flex; 35 | flex-direction: column-reverse; 36 | 37 | ${media.greaterThan("medium")` 38 | flex-direction: column; 39 | `} 40 | 41 | ${media.greaterThan("medium")` 42 | background-color: transparent; 43 | background-position: center; 44 | flex-direction: row; 45 | `} 46 | 47 | ${media.greaterThan("1680px")` 48 | background-position-y: -150px; 49 | `} 50 | 51 | h1 { 52 | font-weight: bold; 53 | font-size: 2.25rem; 54 | margin-bottom: 1.5rem; 55 | line-height: normal; 56 | text-align: right; 57 | color: ${Colors.PRIMARY_COLOR} 58 | 59 | ${media.greaterThan("medium")` 60 | font-size: 3.75rem; 61 | `} 62 | } 63 | 64 | span { 65 | font-family: Hack, monospace; 66 | 67 | ${media.greaterThan("medium")` 68 | font-size: 1.75rem; 69 | `} 70 | } 71 | 72 | i { 73 | animation: ${blink} 1s linear infinite; 74 | } 75 | 76 | div.girl img { 77 | width: calc(100vw - 15vw); 78 | ${media.greaterThan("medium")` 79 | width: 100%; 80 | `} 81 | 82 | } 83 | ` 84 | 85 | const HeroText = styled.div` 86 | display: flex; 87 | ${media.greaterThan("medium")` 88 | align-items: flex-end; 89 | flex-direction: column; 90 | `} 91 | 92 | img { 93 | width: 100%; 94 | ${media.greaterThan("medium")` 95 | width: unset; 96 | margin-top: -20%; 97 | `} 98 | } 99 | ` 100 | 101 | const ProjectsContainer = styled(Container)` 102 | margin-bottom: 1rem; 103 | 104 | ${media.greaterThan("medium")` 105 | margin-bottom: 2.5rem; 106 | `} 107 | ` 108 | 109 | function IndexPage() { 110 | const [projects, setProjects] = useState([]) 111 | const data = useStaticQuery(graphql` 112 | query GetFeaturedProjectsHome { 113 | allFeaturedProjectsJson { 114 | edges { 115 | node { 116 | id 117 | name 118 | slug 119 | owner 120 | repoURL 121 | siteURL 122 | docsURL 123 | description 124 | shortDescription 125 | image { 126 | publicURL 127 | } 128 | } 129 | } 130 | } 131 | } 132 | `) 133 | const featured = data.allFeaturedProjectsJson.edges.map(edge => edge.node) 134 | useEffect(() => { 135 | async function populateProjects() { 136 | getProjects().then(projects => { 137 | setProjects(projects) 138 | }) 139 | } 140 | 141 | populateProjects() 142 | }, []) 143 | 144 | return ( 145 | 151 | 152 | 153 | 154 |
155 | Index Banner 156 |
157 | 158 |
159 |

Addicted Developers

160 |
161 |
162 | By the code 163 |
164 |
165 |
166 |
167 | 168 | 169 | {projects.map((project, i) => ( 170 | 177 | ))} 178 | 179 | 180 | 181 |
182 | ) 183 | } 184 | 185 | export default IndexPage 186 | -------------------------------------------------------------------------------- /src/pages/rules.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import styled from "styled-components" 3 | import media from "styled-media-query" 4 | 5 | import Seo from "@components/Seo" 6 | import Layout, { Container } from "@components/Layout" 7 | import ButtonLink from "@components/ButtonLink" 8 | 9 | import { getIssuesUrl } from "@services/github" 10 | 11 | import BGImage from "@images/2020/background.png" 12 | 13 | const issuesUrl = getIssuesUrl() 14 | 15 | const BGColor = "#201c24" 16 | 17 | const Rules = styled.section` 18 | color: #fff; 19 | line-height: 1.2rem; 20 | h1 { 21 | font-weight: bold; 22 | font-size: 2rem; 23 | margin: 50px 0; 24 | } 25 | h2 { 26 | font-weight: bold; 27 | font-size: 1.5rem; 28 | margin: 20px 0; 29 | } 30 | img { 31 | max-width: 350px; 32 | margin: 0 auto; 33 | display: block; 34 | width: 100%; 35 | } 36 | ul { 37 | list-style-type: circle; 38 | li { 39 | margin-left: 20px; 40 | } 41 | } 42 | ` 43 | 44 | const Projects = styled.section` 45 | padding-top: 5rem; 46 | padding-bottom: 5rem; 47 | color: #fff; 48 | text-align: center; 49 | ` 50 | 51 | const ProjectsTitle = styled.div` 52 | font-weight: bolder; 53 | font-size: 2.25rem; 54 | 55 | ${media.greaterThan("medium")` 56 | font-size: 4rem; 57 | `} 58 | ` 59 | 60 | const ProjectsText = styled.div` 61 | text-align: center; 62 | line-height: 1.75rem; 63 | padding: 2.5rem 0; 64 | 65 | strong { 66 | font-weight: 700; 67 | } 68 | ` 69 | 70 | function RulesPage() { 71 | return ( 72 | 79 | 83 | 84 | 85 | Hacktoberfest Art 90 |

Regras & Valores!

91 |

1 Todos são bem vindos!

92 | Os participantes do Hacktoberfest representaram 151 países e reuniu 93 | milhares de habilidades únicas. Damos as boas-vindas a todos que já 94 | fazem parte da comunidade de software de código aberto e todos que 95 | estão interessados em mergulhar nesse universo. 96 |

2 A quantidade é divertida, a qualidade é a chave.

97 | Participar do Hacktoberfest leva ao crescimento pessoal, oportunidades 98 | profissionais e construção de comunidade. No entanto, tudo começa com 99 | contribuições significativas para o software de código aberto. 100 |

3 Ação de curto prazo, impacto de longo prazo.

101 | Na comunidade de software de código aberto, estamos nos apoiando nos 102 | ombros daqueles que vieram antes de nós. Sua participação tem um 103 | efeito duradouro nas pessoas e na tecnologia, muito depois de outubro. 104 | Esta é uma viagem, não uma corrida. 105 |

Regras de participação.

106 | Para obter uma camisa, você deve ter dois pull requests (PRs) enviados 107 | e pelo menos um aprovado entre 1 e 31 de outubro. Os pull requests 108 | podem ser feitos em qualquer repositório dos projetos open source da 109 | Globo, não apenas para aqueles destacados. O PR deve conter 110 | confirmações que você mesmo fez. Se um mantenedor reportar seu PR como 111 | spam, o mesmo não será contabilizado para sua participação no 112 | Hacktoberfest. Se um mantenedor reportar um comportamento que não 113 | esteja de acordo com o código de conduta do projeto, você não poderá 114 | participar. 115 |

Padrões de qualidade

116 | Em linha com o segundo valor do Hacktoberfest (quantidade é divertida, 117 | qualidade é fundamental), fornecemos exemplos de PR's que consideramos 118 | contribuições de baixa qualidade, as quais são desencorajadas. 119 |
    120 |
  • 121 | PR's que não adicionam valor (por exemplo, scripts para remover 122 | espaços em branco / corrigir erros de digitação / otimizar imagens 123 | / comentários / pequenas traduções / docstrings / documentações 124 | pouco relevantes). 125 |
  • 126 |
  • 127 | PR's que causam interrupções (por exemplo, pegar o branch / 128 | commits de outra pessoa e fazer um PR). 129 |
  • 130 |
  • 131 | PR's que são considerados, pelo mantenedor, um dificultador. 132 |
  • 133 |
  • 134 | Algo que é claramente uma tentativa de simplesmente marcar com +1 135 | sua contagem de PR. 136 |
  • 137 |
138 |
139 |
140 | 141 | 142 | Projetos 143 | 144 | Pull requests podem ser feitos em qualquer projeto{" "} 145 | da Globo 146 | 147 | 148 | Ver issues 149 | 150 | 151 | 152 |
153 | ) 154 | } 155 | 156 | export default RulesPage 157 | -------------------------------------------------------------------------------- /src/components/Layout/Header.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { css } from "styled-components" 4 | import media from "styled-media-query" 5 | import { Link } from "gatsby" 6 | 7 | import Container from "./Container" 8 | import MenuBurguerIcon from "@icons/MenuBurguer" 9 | import GloboComIcon from "@icons/GloboCom" 10 | import Colors from "@constants/colors" 11 | 12 | const HeaderWrapper = styled.header` 13 | height: 3.75rem; 14 | display: flex; 15 | align-items: center; 16 | 17 | ${media.greaterThan("large")` 18 | height: 7.625rem; 19 | `} 20 | 21 | ${props => 22 | props.dark && 23 | css` 24 | background-color: unset; 25 | `} 26 | ` 27 | 28 | const HeaderContainer = styled(Container)` 29 | display: flex; 30 | justify-content: space-between; 31 | align-items: center; 32 | padding-left: 0; 33 | padding-right: 3.75rem; 34 | width: 100%; 35 | height: 100%; 36 | ` 37 | 38 | const MenuBurguer = styled.button` 39 | display: flex; 40 | align-items: center; 41 | background: none; 42 | border: none; 43 | padding: 1rem 1.5rem; 44 | height: 100%; 45 | margin: 0; 46 | cursor: pointer; 47 | white-space: nowrap; 48 | outline: 0; 49 | -webkit-appearance: none; 50 | -webkit-tap-highlight-color: transparent; 51 | 52 | ${media.greaterThan("large")` 53 | display: none; 54 | `} 55 | 56 | svg { 57 | width: 24px; 58 | height: 24px; 59 | fill: ${props => (props.dark ? "#ffffff" : "#000000")}; 60 | } 61 | ` 62 | 63 | const Brand = styled.div` 64 | font-weight: 300; 65 | letter-spacing: -0.025rem; 66 | display: flex; 67 | justify-content: center; 68 | flex: 1; 69 | 70 | ${media.greaterThan("large")` 71 | justify-content: flex-start; 72 | `} 73 | 74 | a { 75 | display: flex; 76 | align-items: center; 77 | color: ${props => (props.dark ? "#ffffff" : "#000000")}; 78 | 79 | svg { 80 | fill: ${props => (props.dark ? "#ffffff" : "#000000")}; 81 | width: 80px; 82 | } 83 | 84 | span { 85 | margin-bottom: 0.125rem; 86 | margin-left: 0.5rem; 87 | } 88 | } 89 | ` 90 | 91 | const Menu = styled.nav` 92 | flex: 2; 93 | font-size: 1rem; 94 | line-height: normal; 95 | letter-spacing: normal; 96 | position: fixed; 97 | top: 0; 98 | left: 0; 99 | width: 260px; 100 | height: 100%; 101 | background-color: #000000; 102 | padding-top: 3rem; 103 | overflow-y: auto; 104 | z-index: 1200; 105 | transition: transform 225ms cubic-bezier(0, 0, 0.2, 1) 0ms; 106 | 107 | ${props => 108 | props.open 109 | ? css` 110 | transform: none; 111 | ` 112 | : css` 113 | transform: translateX(-280px); 114 | pointer-events: none; 115 | visibility: hidden; 116 | `} 117 | 118 | ${media.greaterThan("large")` 119 | font-size: 1.25rem; 120 | position: relative; 121 | top: unset; 122 | left: unset; 123 | width: auto; 124 | height: auto; 125 | background-color: transparent; 126 | padding-top: 0; 127 | z-index: unset; 128 | visibility: visible; 129 | pointer-events: unset; 130 | transform: none; 131 | `} 132 | 133 | ul { 134 | display: flex; 135 | justify-content: flex-end; 136 | flex-direction: column; 137 | 138 | ${media.greaterThan("large")` 139 | flex-direction: row; 140 | `} 141 | 142 | li { 143 | color: #ffffff; 144 | 145 | ${media.greaterThan("large")` 146 | color: ${props => (props.dark ? "#ffffff" : "#000000")}; 147 | margin-left: 2.5rem; 148 | `} 149 | } 150 | } 151 | ` 152 | 153 | const MenuLink = styled(Link)` 154 | color: inherit; 155 | display: block; 156 | padding: 1rem 1.5rem; 157 | 158 | ${media.greaterThan("large")` 159 | padding: 0; 160 | `} 161 | 162 | &.is-active { 163 | /* font-weight: 800; */ 164 | color: ${Colors.PRIMARY_COLOR}; 165 | } 166 | ` 167 | 168 | const MenuLinkHome = styled(MenuLink)` 169 | ${media.greaterThan("large")` 170 | display: none; 171 | `} 172 | ` 173 | 174 | function Header({ dark }) { 175 | const node = useRef() 176 | const [open, setOpen] = useState(false) 177 | const activeClassName = "is-active" 178 | 179 | const handleMenuOpen = () => { 180 | setOpen(true) 181 | } 182 | 183 | const handleMenuCloseOutside = event => { 184 | if (node.current.contains(event.target)) { 185 | return 186 | } 187 | setOpen(false) 188 | } 189 | 190 | useEffect(() => { 191 | document.addEventListener("mousedown", handleMenuCloseOutside) 192 | return () => { 193 | document.removeEventListener("mousedown", handleMenuCloseOutside) 194 | } 195 | }, []) 196 | 197 | return ( 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | Open Source 207 | 208 | 209 | 210 |
    211 |
  • 212 | 213 | Home 214 | 215 |
  • 216 |
  • 217 | 218 | Projetos 219 | 220 |
  • 221 |
  • 222 | 223 | Coders 224 | 225 |
  • 226 |
  • 227 | 228 | Regras & Valores 229 | 230 |
  • 231 |
  • 232 | 233 | Hacktoberfest 234 | 235 |
  • 236 |
237 |
238 |
239 |
240 | ) 241 | } 242 | 243 | Header.propTypes = { 244 | dark: PropTypes.bool, 245 | } 246 | 247 | export default Header 248 | -------------------------------------------------------------------------------- /src/components/HacktoberFestCall/HacktoberFestCall.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react" 2 | import PropTypes from "prop-types" 3 | import styled from "styled-components" 4 | import media from "styled-media-query" 5 | 6 | import ButtonLink from "@components/ButtonLink" 7 | import UserProgress from "./UserProgress" 8 | import { Container } from "@components/Layout" 9 | import { ButtonWrapper } from "@components/Button" 10 | 11 | import { getEdition } from "@services/api" 12 | 13 | import hacktoberFestImg from "@images/2020/astronauta.png" 14 | import hacktoberFestCall from "@images/2020/logo-desktop.png" 15 | import hacktoberFestCallOnly from "@images/2020/hacktober-callonly.png" 16 | import BigBracketImage from "@images/2020/big-bracket.svg" 17 | import year from "@images/2020/year.png" 18 | 19 | const HacktoberFestCallWrapper = styled.section` 20 | margin-bottom: 20px; 21 | color: #fff; 22 | ` 23 | 24 | const EventHeader1 = styled.div` 25 | margin-bottom: 16px; 26 | line-height: 1.4rem; 27 | width: 100%; 28 | text-align: center; 29 | 30 | ${media.greaterThan("medium")` 31 | font-size: 1.75rem; 32 | line-height: 2.3rem; 33 | margin-bottom: 32px; 34 | text-align: unset; 35 | `} 36 | 37 | strong { 38 | font-weight: 700; 39 | } 40 | 41 | span { 42 | display: inline; 43 | ${media.greaterThan("medium")` 44 | display: block; 45 | `} 46 | } 47 | ` 48 | 49 | const EventHeader2 = styled.div` 50 | margin-bottom: 16px; 51 | text-align: center; 52 | font-size: 0.825rem; 53 | 54 | ${media.greaterThan("medium")` 55 | font-size: 1.25rem; 56 | text-align: unset; 57 | margin-bottom: 32px; 58 | `} 59 | ` 60 | 61 | const CallContainer = styled(Container)` 62 | flex-direction: ${props => (props.isCallOnly ? "column-reverse" : "column")}; 63 | display: flex; 64 | justify-content: center; 65 | align-items: center; 66 | 67 | ${media.greaterThan("large")` 68 | flex-direction: row; 69 | `} 70 | 71 | ${media.greaterThan("large")` 72 | justify-content: space-between; 73 | `} 74 | 75 | img { 76 | width: calc(100vw - 8vw); 77 | &.astronaut { 78 | ${media.greaterThan("medium")` 79 | width: 60%; 80 | `} 81 | } 82 | 83 | &.call { 84 | ${media.greaterThan("medium")` 85 | width: 100%; 86 | `} 87 | } 88 | } 89 | ` 90 | 91 | const YearContainer = styled.div` 92 | display: flex; 93 | justify-content: center; 94 | margin: 20px 0px; 95 | img { 96 | width: calc(100vw - 50vw); 97 | ${media.greaterThan("large")` 98 | width: 100%; 99 | `} 100 | } 101 | ` 102 | 103 | const BigBracketContainer = styled.div` 104 | display: flex; 105 | justify-content: center; 106 | img { 107 | width: calc(100vw - 5vw); 108 | ${media.greaterThan("large")` 109 | max-width: 1300px; 110 | width: 100%; 111 | `} 112 | } 113 | ` 114 | 115 | const ActionButtons = styled.div` 116 | text-align: center; 117 | 118 | ${media.greaterThan("medium")` 119 | text-align: left; 120 | `} 121 | ` 122 | 123 | const ButtonRules = styled(ButtonWrapper).attrs({ 124 | as: "a", 125 | })` 126 | background-color: #201c24; 127 | border-color: #fff; 128 | margin-left: 1rem; 129 | 130 | &:hover { 131 | ${media.greaterThan("large")` 132 | border-color: #CCC; 133 | background-color: #141315; 134 | color: #fff; 135 | `} 136 | } 137 | ` 138 | 139 | function HacktoberFestCall({ user, isCallOnly }) { 140 | let [currentEdition, setCurrentEdition] = React.useState(null) 141 | 142 | React.useEffect(() => { 143 | const loadEdition = async () => { 144 | const response = await getEdition() 145 | if (response) { 146 | setCurrentEdition(response.edition) 147 | } 148 | } 149 | loadEdition() 150 | }, []) 151 | 152 | return ( 153 | 154 | {isCallOnly && ( 155 | 156 | {" "} 157 | Big Bracket{" "} 158 | 159 | )} 160 | 161 | Hacktoberfest Art 166 |
174 | Hacktoberfest Art 179 | {isCallOnly && ( 180 | 181 | {" "} 182 | Hacktoberfest Art{" "} 183 | 184 | )} 185 |
186 | 187 | 1 a 31 de outubro 188 | na Globo 189 | 190 | 191 | Contribua e ganhe uma camiseta exclusiva. 192 | 193 | 194 | {isCallOnly ? ( 195 | 196 | Saiba mais 197 | 198 | ) : user && user.edition === currentEdition ? ( 199 | 200 | ) : ( 201 | 202 | 203 | Participar 204 | 205 | 209 | Regras & Valores 210 | 211 | 212 | )} 213 | 214 |
215 |
216 |
217 |
218 | ) 219 | } 220 | 221 | HacktoberFestCall.propTypes = { 222 | user: PropTypes.object, 223 | isCallOnly: PropTypes.bool, 224 | onSignIn: PropTypes.func, 225 | } 226 | 227 | HacktoberFestCall.defaultProps = { 228 | isCallOnly: false, 229 | } 230 | 231 | export default HacktoberFestCall 232 | -------------------------------------------------------------------------------- /src/components/HacktoberFestCall/UserProgress.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState } from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { css } from "styled-components" 4 | import Pluralize from "react-pluralize" 5 | 6 | import Button from "@components/Button" 7 | 8 | import PullRequestIcon from "@icons/PullRequest" 9 | import MergedIcon from "@icons/Merged" 10 | import TShirtIcon from "@icons/TShirt" 11 | import Colors from "@constants/colors" 12 | 13 | import ShippingForm from "./ShippingForm" 14 | 15 | const UserProgressWrapper = styled.div` 16 | color: #cfd3d4; 17 | line-height: 1.75rem; 18 | text-align: left; 19 | 20 | strong { 21 | font-weight: 700; 22 | } 23 | ` 24 | 25 | const Greeting = styled.div` 26 | margin-bottom: 54px; 27 | 28 | strong { 29 | color: ${Colors.PRIMARY_COLOR}; 30 | } 31 | ` 32 | 33 | const Progress = styled.div` 34 | text-align: center; 35 | ` 36 | 37 | const ProgressBody = styled.div` 38 | display: flex; 39 | align-items: center; 40 | ` 41 | 42 | const ProgressLine = styled.div` 43 | flex: 1; 44 | border-top: 3px solid #cfd3d4; 45 | 46 | ${props => 47 | !props.completed 48 | ? css` 49 | color: #cfd3d4; 50 | border-color: #cfd3d4; 51 | ` 52 | : css` 53 | color: ${Colors.PRIMARY_COLOR}; 54 | border-color: ${Colors.PRIMARY_COLOR}; 55 | `} 56 | ` 57 | 58 | const ProgressItem = styled.div` 59 | margin: 0 5px; 60 | width: 60px; 61 | height: 60px; 62 | display: flex; 63 | align-items: center; 64 | justify-content: center; 65 | border-radius: 50%; 66 | border-style: solid; 67 | 68 | ${props => 69 | !props.completed 70 | ? css` 71 | border-width: 3px; 72 | color: #cfd3d4; 73 | border-color: #cfd3d4; 74 | ` 75 | : css` 76 | border-width: 5px; 77 | color: ${Colors.PRIMARY_COLOR}; 78 | border-color: ${Colors.PRIMARY_COLOR}; 79 | `} 80 | ` 81 | 82 | const ProgressStatus = styled.div` 83 | margin: 30px 0; 84 | ` 85 | 86 | const ProgressStatusText = styled.div` 87 | font-family: Hack, monospace; 88 | font-size: 0.875rem; 89 | 90 | strong { 91 | color: ${Colors.PRIMARY_COLOR}; 92 | } 93 | ` 94 | 95 | const ProgressStatusActions = styled.div` 96 | margin-top: 30px; 97 | ` 98 | 99 | const Achievement = styled.div` 100 | display: flex; 101 | align-items: center; 102 | font-weight: 600; 103 | 104 | span { 105 | margin-right: 0.2rem; 106 | } 107 | 108 | svg { 109 | color: inherit; 110 | width: 25px; 111 | height: auto; 112 | } 113 | ` 114 | 115 | const AchievementPRs = styled(Achievement)` 116 | font-size: 1rem; 117 | 118 | svg { 119 | width: 18px; 120 | } 121 | ` 122 | 123 | function UserProgress({ user }) { 124 | const { hacktoberfest } = user 125 | const { progress } = hacktoberfest 126 | const { achievements } = hacktoberfest.progress 127 | 128 | // Used for testing 129 | const isStaff = ["arturfsousa", "guilhermebr", "marcelometal"].includes( 130 | user.githubUser 131 | ) 132 | 133 | const completed = 134 | isStaff || 135 | (achievements.opened && achievements.merged && achievements.firsts) 136 | 137 | const [open, setOpen] = useState(false) 138 | 139 | function handleOpen() { 140 | setOpen(true) 141 | } 142 | 143 | function handleClose() { 144 | setOpen(false) 145 | } 146 | 147 | return ( 148 | 149 | 150 | 151 | 152 | Olá @{user.githubUser}!
153 | Você está participando da{" "} 154 | Hacktoberfest {hacktoberfest.edition}. Acompanhe seu 155 | progresso: 156 |
157 | 158 | 159 | 160 | 161 | 2 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | {!completed ? ( 180 | achievements.opened ? ( 181 | 182 | Você tem{" "} 183 | 184 | 189 | {" "} 190 | e{" "} 191 | 192 | 197 | 198 | 199 | ) : ( 200 | 201 | Você ainda não enviou nenhum pull request! 202 | 203 | ) 204 | ) : ( 205 | 206 | Parabéns! Você concluiu o desafio da 207 | Hacktoberfest{" "} 208 | 209 | 💪🏆 210 | 211 | . Clique no botão abaixo para informar o endereço de envio e o 212 | tamanho da sua camiseta: 213 | 214 | )} 215 | {completed && ( 216 | 217 | 220 | 221 | )} 222 | 223 | 224 |
225 |
226 | ) 227 | } 228 | 229 | UserProgress.propTypes = { 230 | user: PropTypes.object.isRequired, 231 | } 232 | 233 | export default UserProgress 234 | -------------------------------------------------------------------------------- /src/components/HacktoberFestCall/ShippingForm.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState, useEffect } from "react" 2 | 3 | import * as Yup from "yup" 4 | import { withFormik } from "formik" 5 | 6 | import Dialog, { 7 | DialogTitle, 8 | DialogBody, 9 | DialogFooter, 10 | DialogText, 11 | } from "@components/Dialog" 12 | 13 | import Button from "@components/Button" 14 | import TextInput from "@components/TextInput" 15 | import SelectInput from "@components/SelectInput" 16 | import Message from "@components/Message" 17 | 18 | import { updateUser } from "@services/api" 19 | 20 | function ShippingForm({ 21 | open, 22 | handleClose, 23 | values, 24 | touched, 25 | errors, 26 | handleChange, 27 | handleBlur, 28 | handleSubmit, 29 | status, 30 | }) { 31 | const [showMessage, setShowMessage] = useState(false) 32 | 33 | useEffect(() => { 34 | if (status && status.completed) { 35 | handleClose() 36 | setShowMessage(true) 37 | 38 | window.setTimeout(() => { 39 | setShowMessage(false) 40 | }, 6000) 41 | } 42 | // https://github.com/facebook/create-react-app/issues/6880 43 | // eslint-disable-next-line react-hooks/exhaustive-deps 44 | }, [status]) 45 | 46 | return ( 47 | 48 | {showMessage && status && status.success && ( 49 | Dados enviados com sucesso! 50 | )} 51 | {showMessage && status && !status.success && ( 52 | 53 | Houve uma falha na alteração dos seus dados! Tente novamente. 54 | 55 | )} 56 | 61 | Dados para entrega 62 | 63 | 64 | Informe os dados para entrega da sua camiseta: 65 | 66 |
67 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 96 | 106 | 116 | 126 | 136 | 146 | 147 |
148 | 149 | 150 | 153 | 154 |
155 |
156 | ) 157 | } 158 | 159 | export default withFormik({ 160 | mapPropsToValues: ({ user }) => ({ 161 | shirtsize: user.shirtSize, 162 | name: user.name, 163 | email: user.email, 164 | state: user.state, 165 | city: user.city, 166 | address: user.address, 167 | postalCode: user.postalCode, 168 | }), 169 | 170 | validationSchema: Yup.object().shape({ 171 | shirtsize: Yup.string().required("Preenchimento obrigatório."), 172 | name: Yup.string().required("Preenchimento obrigatório."), 173 | email: Yup.string() 174 | .email("E-mail Inválido.") 175 | .required("Preenchimento obrigatório."), 176 | state: Yup.string().required("Preenchimento obrigatório."), 177 | city: Yup.string().required("Preenchimento obrigatório."), 178 | address: Yup.string().required("Preenchimento obrigatório."), 179 | postalCode: Yup.string() 180 | .required("Preenchimento obrigatório.") 181 | .min(8, "Cep deve possuir 8 dígitos"), 182 | }), 183 | 184 | handleSubmit: async (values, { setSubmitting, setStatus }) => { 185 | const user = await updateUser(values) 186 | setStatus({ success: Boolean(user), completed: true }) 187 | setSubmitting(false) 188 | }, 189 | 190 | displayName: "ShippingForm", 191 | })(ShippingForm) 192 | -------------------------------------------------------------------------------- /src/components/Project/Project.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react" 2 | import PropTypes from "prop-types" 3 | import styled, { css } from "styled-components" 4 | import media from "styled-media-query" 5 | 6 | import iconExpandLess from "@images/icons/expand-less.svg" 7 | import iconExpandMore from "@images/icons/expand-more.svg" 8 | 9 | import starsIcon from "@images/icons/stars" 10 | import iconCommits from "@images/icons/commits" 11 | import iconPrs from "@images/icons/prs" 12 | import iconIssues from "@images/icons/issues" 13 | 14 | import Colors from "@constants/colors" 15 | 16 | import BracketImage from "@images/2020/open-bracket.svg" 17 | 18 | const REPOSITORY_COUNT_ICONS = { 19 | stars: home => () => starsIcon(home), 20 | commits: home => () => iconCommits(home), 21 | prs: home => () => iconPrs(home), 22 | issues: home => () => iconIssues(home), 23 | } 24 | 25 | const ProjectWrapper = styled.div` 26 | display: flex; 27 | flex-direction: column; 28 | ${props => 29 | !props.isFeatured && 30 | css` 31 | margin-bottom: 1.7rem; 32 | border-bottom: 1px solid ${Colors.PRIMARY_COLOR}; 33 | `} 34 | ` 35 | 36 | const ProjectDetails = styled.div` 37 | display: flex; 38 | flex-direction: column; 39 | justify-content: space-between; 40 | height: 100%; 41 | ${props => 42 | !props.isFeatured && 43 | ` 44 | align-items: flex-start; 45 | `} 46 | transition: visibility 225ms; 47 | ${props => 48 | !props.open 49 | ? css` 50 | display: none; 51 | visibility: hidden; 52 | ` 53 | : css` 54 | visibility: visible; 55 | `} 56 | ${media.greaterThan("medium")` 57 | visibility: visible; 58 | ${props => 59 | props.isFeatured && 60 | ` 61 | display: inherit; 62 | `} 63 | `} 64 | ` 65 | 66 | const ProjectName = styled.h2` 67 | flex: 1; 68 | font-size: 1.6rem; 69 | font-weight: bold; 70 | color: ${props => (props.home ? "#fff" : "#000")}; 71 | display: flex; 72 | justify-content: center; 73 | align-items: center; 74 | ${media.greaterThan("medium")` 75 | height: 80px; 76 | `} 77 | ` 78 | 79 | const ProjectDescription = styled.p` 80 | padding: 1.5rem 0; 81 | line-height: 1.25; 82 | color: ${props => (props.home ? "#fff" : "#000")}; 83 | letter-spacing: 0.4px; 84 | text-align: ${props => (!props.isFeatured ? "left" : "center")}; 85 | ` 86 | 87 | const ProjectWebSite = styled.a` 88 | display: block; 89 | text-align: center; 90 | color: ${Colors.PRIMARY_COLOR}; 91 | font-weight: bold; 92 | &:hover { 93 | text-decoration: underline; 94 | } 95 | ` 96 | 97 | const ProjectLinks = styled.div` 98 | padding: 1.5rem 0; 99 | display: flex; 100 | align-items: center; 101 | justify-content: space-around; 102 | ${props => 103 | !props.isFeatured && 104 | ` 105 | width: 100%; 106 | justify-content: space-between; 107 | `} 108 | ` 109 | 110 | const ProjectLink = styled.a` 111 | font-weight: bold; 112 | color: ${props => (props.home ? "#fff" : "#000")}; 113 | padding: ${props => (props.home ? "0px 10px" : "0px")}; 114 | ` 115 | 116 | const Nav = styled.div` 117 | padding: 20px 0; 118 | padding-left: 24px; 119 | display: flex; 120 | justify-content: space-between; 121 | align-items: center; 122 | ${media.greaterThan("medium")` 123 | padding: 1.5rem 0; 124 | height: 80px; 125 | `} 126 | ` 127 | 128 | const NavButton = styled.i` 129 | width: 24px; 130 | height: 24px; 131 | ${props => 132 | props.open 133 | ? css` 134 | background-image: url(${iconExpandLess}); 135 | ` 136 | : css` 137 | background-image: url(${iconExpandMore}); 138 | `} 139 | ${media.greaterThan("medium")` 140 | display: none; 141 | `} 142 | ` 143 | 144 | const ImageWrapper = styled.div` 145 | text-align: center; 146 | flex: 1; 147 | ` 148 | 149 | const RepoInfo = styled.div` 150 | padding: 1.5rem 0 1rem; 151 | display: flex; 152 | justify-content: space-between; 153 | grid-template-columns: repeat(5, 1fr); 154 | grid-gap: ${props => (props.home ? "0px" : "35px")}; 155 | ` 156 | 157 | const RepoCounterWrapper = styled.div` 158 | color: #757575; 159 | display: flex; 160 | align-items: center; 161 | justify-content: center; 162 | flex-direction: column; 163 | ` 164 | 165 | const RepoCounterIcon = styled.i` 166 | width: 30px; 167 | height: 20px; 168 | display: inline-block; 169 | background-position: center; 170 | margin-bottom: 10px; 171 | text-align: center; 172 | ` 173 | 174 | const Bracket = styled.img` 175 | transform: scaleX(${props => (props.inverted ? -1 : 1)}); 176 | width: ${props => (props.width ? props.width : "26px")}; 177 | ` 178 | 179 | const StyledBracketWrapper = styled.div` 180 | display: flex; 181 | align-items: center; 182 | ` 183 | 184 | const BracketWrapper = props => { 185 | return ( 186 | 187 | {props.home && } 188 | {props.children} 189 | {props.home && ( 190 | 191 | )} 192 | 193 | ) 194 | } 195 | 196 | function RepoCounter({ name, count, home }) { 197 | const Icon = REPOSITORY_COUNT_ICONS[name](home) 198 | 199 | return ( 200 | 201 | 202 | 203 | 204 | 205 | {count === undefined ? "00000" : count} 206 | 207 | 208 | ) 209 | } 210 | 211 | RepoCounter.propTypes = { 212 | name: PropTypes.string.isRequired, 213 | count: PropTypes.number, 214 | } 215 | 216 | function Project(props) { 217 | const { 218 | name, 219 | image, 220 | siteURL, 221 | repoURL = "//", 222 | docsURL, 223 | shortDescription, 224 | description, 225 | isFirst, 226 | isFeatured, 227 | repoNumbers, 228 | home, 229 | } = props 230 | 231 | const [open, setOpen] = useState(isFirst) 232 | 233 | function handleToggleOpen() { 234 | setOpen(!open) 235 | } 236 | 237 | return ( 238 | 239 | 249 | {repoNumbers && ( 250 | 251 | 255 | 256 | 261 | 262 | 263 | 264 | 265 | )} 266 | 267 | 272 | {(shortDescription || description) && ( 273 | 274 | {shortDescription || description} 275 | 276 | )} 277 | 278 | {siteURL && ( 279 | 284 | {siteURL} 285 | 286 | )} 287 | 288 | {repoURL && ( 289 | 290 | 296 | {isFeatured ? "Repositório" : "Ver repositório"} 297 | 298 | 299 | )} 300 | {docsURL && ( 301 | 302 | 308 | Documentação 309 | 310 | 311 | )} 312 | 313 | 314 | 315 | ) 316 | } 317 | 318 | Project.propTypes = { 319 | isFirst: PropTypes.bool.isRequired, 320 | isFeatured: PropTypes.bool.isRequired, 321 | name: PropTypes.string.isRequired, 322 | image: PropTypes.object, 323 | repoURL: PropTypes.string.isRequired, 324 | siteURL: PropTypes.string, 325 | docsURL: PropTypes.string, 326 | shortDescription: PropTypes.string, 327 | description: PropTypes.string, 328 | repoNumbers: PropTypes.object, 329 | home: PropTypes.bool, 330 | } 331 | 332 | Project.defaultProps = { 333 | isFirst: false, 334 | isFeatured: false, 335 | } 336 | 337 | export default Project 338 | -------------------------------------------------------------------------------- /data/logos/megadraft.svg: -------------------------------------------------------------------------------- 1 | 2 | v2_logo -------------------------------------------------------------------------------- /api/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "edition": { 3 | "success": true, 4 | "status": 200, 5 | "type": "ok", 6 | "result": { 7 | "edition": 2020, 8 | "id": "872485b5-ff40-4448-9658-be866a387080" 9 | } 10 | }, 11 | "projects": { 12 | "success": true, 13 | "status": 200, 14 | "type": "ok", 15 | "result": { 16 | "items": [ 17 | { 18 | "name": "Tsuru", 19 | "website": "https://tsuru.io", 20 | "repositoryUrl": "https://github.com/tsuru/tsuru", 21 | "featured": true, 22 | "imageUrl": { 23 | "thumborUrl": "https://github.com/globocom/opensource/raw/master/static/images/opengraph.png" 24 | }, 25 | "documentationUrl": "https://docs.tsuru.io/stable/", 26 | "description": "Open source, extensible and Docker-based Platform as a Service (PaaS).", 27 | "stats": { 28 | "repository": { 29 | "object": { 30 | "commit": { 31 | "history": { 32 | "totalCount": 15010 33 | } 34 | } 35 | }, 36 | "issues": { 37 | "totalCount": 1491 38 | }, 39 | "pullRequests": { 40 | "totalCount": 950 41 | }, 42 | "stars": { 43 | "totalCount": 3405 44 | } 45 | } 46 | } 47 | }, 48 | { 49 | "name": "Thumbor", 50 | "website": "http://thumbor.org/", 51 | "repositoryUrl": "https://github.com/thumbor/thumbor", 52 | "featured": true, 53 | "imageUrl": { 54 | "thumborUrl": "https://github.com/globocom/opensource/raw/master/static/images/opengraph.png" 55 | }, 56 | "documentationUrl": "https://thumbor.readthedocs.io/en/latest/index.html", 57 | "description": "Thumbor is an open-source photo thumbnail service by globo.com.", 58 | "stats": { 59 | "repository": { 60 | "object": { 61 | "commit": { 62 | "history": { 63 | "totalCount": 2202 64 | } 65 | } 66 | }, 67 | "issues": { 68 | "totalCount": 825 69 | }, 70 | "pullRequests": { 71 | "totalCount": 493 72 | }, 73 | "stars": { 74 | "totalCount": 7989 75 | } 76 | } 77 | } 78 | }, 79 | { 80 | "name": "Clappr", 81 | "website": "http://clappr.io/", 82 | "repositoryUrl": "https://github.com/clappr/clappr", 83 | "featured": true, 84 | "imageUrl": { 85 | "thumborUrl": "https://github.com/globocom/opensource/raw/master/static/images/opengraph.png" 86 | }, 87 | "documentationUrl": "https://clappr.github.io/", 88 | "description": "An extensible media player for the web.", 89 | "stats": { 90 | "repository": { 91 | "object": { 92 | "commit": { 93 | "history": { 94 | "totalCount": 4185 95 | } 96 | } 97 | }, 98 | "issues": { 99 | "totalCount": 1364 100 | }, 101 | "pullRequests": { 102 | "totalCount": 601 103 | }, 104 | "stars": { 105 | "totalCount": 5084 106 | } 107 | } 108 | } 109 | }, 110 | { 111 | "name": "huskyCI", 112 | "website": "https://huskyci.opensource.globo.com/", 113 | "repositoryUrl": "https://github.com/globocom/huskyCI", 114 | "featured": true, 115 | "imageUrl": { 116 | "thumborUrl": "https://github.com/globocom/opensource/raw/master/static/images/opengraph.png" 117 | }, 118 | "documentationUrl": "https://huskyci.opensource.globo.com/docs/quickstart/overview", 119 | "description": "Performing security tests inside your CI.", 120 | "stats": { 121 | "repository": { 122 | "object": { 123 | "commit": { 124 | "history": { 125 | "totalCount": 1006 126 | } 127 | } 128 | }, 129 | "issues": { 130 | "totalCount": 169 131 | }, 132 | "pullRequests": { 133 | "totalCount": 350 134 | }, 135 | "stars": { 136 | "totalCount": 352 137 | } 138 | } 139 | } 140 | }, 141 | { 142 | "name": "Megadraft", 143 | "website": "http://megadraft.io/", 144 | "repositoryUrl": "https://github.com/globocom/megadraft", 145 | "featured": true, 146 | "imageUrl": { 147 | "thumborUrl": "https://github.com/globocom/opensource/raw/master/static/images/opengraph.png" 148 | }, 149 | "documentationUrl": "http://megadraft.io/#/docs/overview", 150 | "description": "Megadraft is a Rich Text editor built on top of Facebook's Draft.JS featuring a nice default base of components and extensibility.", 151 | "stats": { 152 | "repository": { 153 | "object": { 154 | "commit": { 155 | "history": { 156 | "totalCount": 579 157 | } 158 | } 159 | }, 160 | "issues": { 161 | "totalCount": 144 162 | }, 163 | "pullRequests": { 164 | "totalCount": 184 165 | }, 166 | "stars": { 167 | "totalCount": 949 168 | } 169 | } 170 | } 171 | }, 172 | { 173 | "name": "Fastlane Queue", 174 | "website": "", 175 | "repositoryUrl": "https://github.com/fastlane-queue", 176 | "featured": false, 177 | "documentationUrl": "https://fastlane.readthedocs.io/", 178 | "description": "More seriously, though, fastlane allows you to easily implement new workers in the form of containers." 179 | }, 180 | { 181 | "name": "secDevLabs", 182 | "website": "", 183 | "repositoryUrl": "https://github.com/globocom/secDevLabs", 184 | "featured": true, 185 | "imageUrl": { 186 | "thumborUrl": "https://github.com/globocom/opensource/raw/master/static/images/opengraph.png" 187 | }, 188 | "documentationUrl": "https://github.com/globocom/secDevLabs/blob/master/README.md", 189 | "description": "A laboratory for learning secure web and mobile development in a practical manner.", 190 | "stats": { 191 | "repository": { 192 | "object": { 193 | "commit": { 194 | "history": { 195 | "totalCount": 645 196 | } 197 | } 198 | }, 199 | "issues": { 200 | "totalCount": 58 201 | }, 202 | "pullRequests": { 203 | "totalCount": 383 204 | }, 205 | "stars": { 206 | "totalCount": 509 207 | } 208 | } 209 | } 210 | }, 211 | { 212 | "name": "Pretty Log", 213 | "website": "", 214 | "repositoryUrl": "https://github.com/globocom/prettylog", 215 | "featured": false, 216 | "documentationUrl": "https://github.com/globocom/prettylog/blob/master/README.md", 217 | "description": "Ferramenta para exibição de logs estruturados em JSON em formato compatível com seres humanos." 218 | }, 219 | { 220 | "name": "GSH", 221 | "website": "", 222 | "repositoryUrl": "https://github.com/globocom/gsh", 223 | "featured": false, 224 | "documentationUrl": "https://github.com/globocom/gsh/blob/master/README.md", 225 | "description": "GSH is an OpenID Connect-compatible authentication system for systems using OpenSSH servers consisting of an out-of-box binary set." 226 | }, 227 | { 228 | "name": "Globo Network API", 229 | "website": "", 230 | "repositoryUrl": "https://github.com/globocom/GloboNetworkAPI", 231 | "featured": false, 232 | "documentationUrl": "https://globonetworkapi.readthedocs.io/en/latest/", 233 | "description": "Globo NetworkAPI is a REST API that manages IP networking resources." 234 | }, 235 | { 236 | "name": "huskyCI Dashboard", 237 | "website": "", 238 | "repositoryUrl": "https://github.com/globocom/huskyCI-dashboard", 239 | "featured": false, 240 | "documentationUrl": "https://github.com/globocom/huskyCI-dashboard/blob/master/README.md", 241 | "description": "This project provides a front-end for every huskyCI user to check the stats of the analyses done." 242 | }, 243 | { 244 | "name": "SLO Generator", 245 | "website": "", 246 | "repositoryUrl": "https://github.com/globocom/slo-generator", 247 | "featured": false, 248 | "documentationUrl": "https://github.com/globocom/slo-generator/blob/master/README.md", 249 | "description": "Easily setup a service level objective using prometheus, based on lessons from the SRE workbook." 250 | }, 251 | { 252 | "name": "M3U8", 253 | "website": "", 254 | "repositoryUrl": "https://github.com/globocom/m3u8", 255 | "featured": false, 256 | "documentationUrl": "https://github.com/globocom/m3u8/blob/master/README.rst", 257 | "description": "Python m3u8 parser." 258 | }, 259 | { 260 | "name": "Gedis", 261 | "website": "", 262 | "repositoryUrl": "https://github.com/globocom/gedis/", 263 | "featured": false, 264 | "documentationUrl": "https://github.com/globocom/gedis/blob/master/README.md", 265 | "description": "Resilient Jedis adapter for Scala made with love by Globo.com" 266 | }, 267 | { 268 | "name": "GCloud Utils", 269 | "website": "", 270 | "repositoryUrl": "https://github.com/globocom/gcloud-utils", 271 | "featured": false, 272 | "documentationUrl": "https://github.com/globocom/gcloud-utils/blob/master/README.md", 273 | "description": "Global package for Cloud Management" 274 | }, 275 | { 276 | "name": "GHDFS", 277 | "website": "", 278 | "repositoryUrl": "https://github.com/globocom/ghdfs/", 279 | "featured": false, 280 | "documentationUrl": "https://github.com/globocom/ghdfs/blob/master/README.md", 281 | "description": "Works with HDFS for common operations and Scala compatibility." 282 | }, 283 | { 284 | "name": "Echo Prometheus", 285 | "website": "", 286 | "repositoryUrl": "https://github.com/globocom/echo-prometheus", 287 | "featured": false, 288 | "documentationUrl": "https://github.com/globocom/echo-prometheus/blob/master/README.md", 289 | "description": "Middleware for echo v4 to instrument all handlers as metrics" 290 | }, 291 | { 292 | "name": "Azkaban CLI", 293 | "website": "", 294 | "repositoryUrl": "https://github.com/globocom/azkaban-cli", 295 | "featured": false, 296 | "documentationUrl": "https://github.com/globocom/azkaban-cli/blob/master/README.md", 297 | "description": "CLI for Azkaban 3 API access and flow upload." 298 | }, 299 | { 300 | "name": "Auror Core", 301 | "website": "", 302 | "repositoryUrl": "https://github.com/globocom/auror-core", 303 | "featured": false, 304 | "documentationUrl": "https://github.com/globocom/auror-core/blob/master/README.md", 305 | "description": "Simple Flow creation for Azkaban" 306 | }, 307 | { 308 | "name": "Backstage Functions", 309 | "website": "", 310 | "repositoryUrl": "https://github.com/globocom/functions", 311 | "featured": false, 312 | "documentationUrl": "https://github.com/globocom/functions/blob/master/README.md", 313 | "description": "Backstage Functions is an Open Source Serverless Platform able to store and execute code." 314 | }, 315 | { 316 | "name": "Globo Network API Web UI", 317 | "website": "", 318 | "repositoryUrl": "https://github.com/globocom/GloboNetworkAPI-Webui", 319 | "featured": false, 320 | "documentationUrl": "https://github.com/globocom/GloboNetworkAPI-WebUI/blob/master/README.md", 321 | "description": "This web tool helps network administrator manage and automate networking resources (routers, switches and load balancers) and document logical and physical networking." 322 | }, 323 | { 324 | "name": "GoReq", 325 | "website": "", 326 | "repositoryUrl": "https://github.com/globocom/goreq", 327 | "featured": false, 328 | "documentationUrl": "https://github.com/globocom/goreq/blob/master/README.md", 329 | "description": "Simple and sane HTTP request library for Go language." 330 | } 331 | ] 332 | } 333 | }, 334 | "user": { 335 | "success": true, 336 | "status": 200, 337 | "type": "ok", 338 | "result": { 339 | "id": "my-id", 340 | "name": "Artur", 341 | "email": "meuemail@gmail.com", 342 | "state": "RJ", 343 | "city": "Rio de Janeiro", 344 | "address": "Meu endereço", 345 | "postalCode": "12345678", 346 | "shirtSize": "TSGG", 347 | "avatarURL": "https://avatars0.githubusercontent.com/u/1333599?v=4", 348 | "githubUser": "arturfsousa", 349 | "githubID": "120391203", 350 | "edition": 2019, 351 | "approved": true, 352 | "completed": true, 353 | "completed_at": "2019-10-29T11:33:53.708817532-03:00", 354 | "totalMergeRequests": 2, 355 | "totalMergeRequestsMerged": 2, 356 | "hacktoberfest": { 357 | "edition": 2019, 358 | "progress": { 359 | "opened": 2, 360 | "merged": 2, 361 | "achievements": { 362 | "opened": true, 363 | "merged": true, 364 | "firsts": true, 365 | "completed": true 366 | } 367 | } 368 | }, 369 | "shirtsize": "TSGG" 370 | } 371 | }, 372 | "status": { 373 | "success": true, 374 | "status": 200, 375 | "type": "ok", 376 | "result": [ 377 | { 378 | "githubID": "11424945", 379 | "githubUser": "joserenatosilva", 380 | "avatar": "https://avatars0.githubusercontent.com/u/11424945?v=4", 381 | "total_pull_requests": 15, 382 | "approved": true 383 | }, 384 | { 385 | "githubID": "8943477", 386 | "githubUser": "rafaveira3", 387 | "avatar": "https://avatars0.githubusercontent.com/u/8943477?v=4", 388 | "total_pull_requests": 15, 389 | "approved": true 390 | }, 391 | { 392 | "githubID": "11041", 393 | "githubUser": "cezarsa", 394 | "avatar": "https://avatars1.githubusercontent.com/u/11041?v=4", 395 | "total_pull_requests": 12, 396 | "approved": true 397 | }, 398 | { 399 | "githubID": "1398357", 400 | "githubUser": "juliolustosa", 401 | "avatar": "https://avatars0.githubusercontent.com/u/1398357?v=4", 402 | "total_pull_requests": 11, 403 | "approved": true 404 | }, 405 | { 406 | "githubID": "31575324", 407 | "githubUser": "arthurcgc", 408 | "avatar": "https://avatars3.githubusercontent.com/u/31575324?v=4", 409 | "total_pull_requests": 9, 410 | "approved": true 411 | }, 412 | { 413 | "githubID": "34755896", 414 | "githubUser": "viniciusbds", 415 | "avatar": "https://avatars3.githubusercontent.com/u/34755896?v=4", 416 | "total_pull_requests": 9, 417 | "approved": true 418 | }, 419 | { 420 | "githubID": "7503687", 421 | "githubUser": "nettoclaudio", 422 | "avatar": "https://avatars0.githubusercontent.com/u/7503687?v=4", 423 | "total_pull_requests": 8, 424 | "approved": true 425 | }, 426 | { 427 | "githubID": "56852949", 428 | "githubUser": "bgbombas", 429 | "avatar": "https://avatars1.githubusercontent.com/u/56852949?v=4", 430 | "total_pull_requests": 8, 431 | "approved": false 432 | }, 433 | { 434 | "githubID": "55638", 435 | "githubUser": "morpheu", 436 | "avatar": "https://avatars0.githubusercontent.com/u/55638?v=4", 437 | "total_pull_requests": 5, 438 | "approved": true 439 | }, 440 | { 441 | "githubID": "665903", 442 | "githubUser": "marcelometal", 443 | "avatar": "https://avatars1.githubusercontent.com/u/665903?v=4", 444 | "total_pull_requests": 5, 445 | "approved": true 446 | }, 447 | { 448 | "githubID": "25726888", 449 | "githubUser": "Rickecr", 450 | "avatar": "https://avatars2.githubusercontent.com/u/25726888?v=4", 451 | "total_pull_requests": 5, 452 | "approved": true 453 | }, 454 | { 455 | "githubID": "18303", 456 | "githubUser": "pedrokiefer", 457 | "avatar": "https://avatars1.githubusercontent.com/u/18303?v=4", 458 | "total_pull_requests": 4, 459 | "approved": true 460 | }, 461 | { 462 | "githubID": "18516908", 463 | "githubUser": "Perkles", 464 | "avatar": "https://avatars0.githubusercontent.com/u/18516908?v=4", 465 | "total_pull_requests": 4, 466 | "approved": true 467 | }, 468 | { 469 | "githubID": "6402131", 470 | "githubUser": "bernardolins", 471 | "avatar": "https://avatars1.githubusercontent.com/u/6402131?v=4", 472 | "total_pull_requests": 4, 473 | "approved": true 474 | }, 475 | { 476 | "githubID": "331817", 477 | "githubUser": "guilhermebr", 478 | "avatar": "https://avatars1.githubusercontent.com/u/331817?v=4", 479 | "total_pull_requests": 4, 480 | "approved": true 481 | }, 482 | { 483 | "githubID": "354110", 484 | "githubUser": "hermancaldara", 485 | "avatar": "https://avatars0.githubusercontent.com/u/354110?v=4", 486 | "total_pull_requests": 4, 487 | "approved": true 488 | }, 489 | { 490 | "githubID": "30700596", 491 | "githubUser": "hericlesme", 492 | "avatar": "https://avatars2.githubusercontent.com/u/30700596?v=4", 493 | "total_pull_requests": 4, 494 | "approved": true 495 | }, 496 | { 497 | "githubID": "271259", 498 | "githubUser": "heliocorreia", 499 | "avatar": "https://avatars2.githubusercontent.com/u/271259?v=4", 500 | "total_pull_requests": 4, 501 | "approved": true 502 | }, 503 | { 504 | "githubID": "25057248", 505 | "githubUser": "Koalapvh13", 506 | "avatar": "https://avatars1.githubusercontent.com/u/25057248?v=4", 507 | "total_pull_requests": 4, 508 | "approved": true 509 | }, 510 | { 511 | "githubID": "10122339", 512 | "githubUser": "icarodgl", 513 | "avatar": "https://avatars0.githubusercontent.com/u/10122339?v=4", 514 | "total_pull_requests": 4, 515 | "approved": true 516 | }, 517 | { 518 | "githubID": "44512806", 519 | "githubUser": "sabrinabs", 520 | "avatar": "https://avatars0.githubusercontent.com/u/44512806?v=4", 521 | "total_pull_requests": 4, 522 | "approved": false 523 | }, 524 | { 525 | "githubID": "7620947", 526 | "githubUser": "rodrigo-brito", 527 | "avatar": "https://avatars0.githubusercontent.com/u/7620947?v=4", 528 | "total_pull_requests": 3, 529 | "approved": true 530 | }, 531 | { 532 | "githubID": "4116980", 533 | "githubUser": "brunoocasali", 534 | "avatar": "https://avatars1.githubusercontent.com/u/4116980?v=4", 535 | "total_pull_requests": 3, 536 | "approved": true 537 | }, 538 | { 539 | "githubID": "6751242", 540 | "githubUser": "MarcosEllys", 541 | "avatar": "https://avatars3.githubusercontent.com/u/6751242?v=4", 542 | "total_pull_requests": 3, 543 | "approved": true 544 | }, 545 | { 546 | "githubID": "23871115", 547 | "githubUser": "allanassis", 548 | "avatar": "https://avatars0.githubusercontent.com/u/23871115?v=4", 549 | "total_pull_requests": 3, 550 | "approved": true 551 | }, 552 | { 553 | "githubID": "6810985", 554 | "githubUser": "wdtamagi", 555 | "avatar": "https://avatars1.githubusercontent.com/u/6810985?v=4", 556 | "total_pull_requests": 3, 557 | "approved": true 558 | }, 559 | { 560 | "githubID": "43251314", 561 | "githubUser": "AyrtonCossuol", 562 | "avatar": "https://avatars2.githubusercontent.com/u/43251314?v=4", 563 | "total_pull_requests": 3, 564 | "approved": true 565 | }, 566 | { 567 | "githubID": "11907615", 568 | "githubUser": "xpecex", 569 | "avatar": "https://avatars3.githubusercontent.com/u/11907615?v=4", 570 | "total_pull_requests": 3, 571 | "approved": true 572 | }, 573 | { 574 | "githubID": "33502846", 575 | "githubUser": "jessescn", 576 | "avatar": "https://avatars1.githubusercontent.com/u/33502846?v=4", 577 | "total_pull_requests": 3, 578 | "approved": true 579 | }, 580 | { 581 | "githubID": "15738138", 582 | "githubUser": "rafaelrubbioli", 583 | "avatar": "https://avatars3.githubusercontent.com/u/15738138?v=4", 584 | "total_pull_requests": 3, 585 | "approved": true 586 | }, 587 | { 588 | "githubID": "24421664", 589 | "githubUser": "GMVargass", 590 | "avatar": "https://avatars0.githubusercontent.com/u/24421664?v=4", 591 | "total_pull_requests": 3, 592 | "approved": true 593 | }, 594 | { 595 | "githubID": "19228139", 596 | "githubUser": "Paulophmp", 597 | "avatar": "https://avatars3.githubusercontent.com/u/19228139?v=4", 598 | "total_pull_requests": 3, 599 | "approved": true 600 | }, 601 | { 602 | "githubID": "38760797", 603 | "githubUser": "luanabm", 604 | "avatar": "https://avatars0.githubusercontent.com/u/38760797?v=4", 605 | "total_pull_requests": 3, 606 | "approved": true 607 | }, 608 | { 609 | "githubID": "8585270", 610 | "githubUser": "Natan7", 611 | "avatar": "https://avatars3.githubusercontent.com/u/8585270?v=4", 612 | "total_pull_requests": 3, 613 | "approved": false 614 | }, 615 | { 616 | "githubID": "21161579", 617 | "githubUser": "luiz-mai", 618 | "avatar": "https://avatars3.githubusercontent.com/u/21161579?v=4", 619 | "total_pull_requests": 3, 620 | "approved": false 621 | }, 622 | { 623 | "githubID": "13488025", 624 | "githubUser": "jadsonluan", 625 | "avatar": "https://avatars2.githubusercontent.com/u/13488025?v=4", 626 | "total_pull_requests": 3, 627 | "approved": false 628 | }, 629 | { 630 | "githubID": "29151666", 631 | "githubUser": "DavidMoura07", 632 | "avatar": "https://avatars2.githubusercontent.com/u/29151666?v=4", 633 | "total_pull_requests": 3, 634 | "approved": false 635 | }, 636 | { 637 | "githubID": "39952041", 638 | "githubUser": "IgorSilveira7", 639 | "avatar": "https://avatars3.githubusercontent.com/u/39952041?v=4", 640 | "total_pull_requests": 3, 641 | "approved": false 642 | }, 643 | { 644 | "githubID": "860741", 645 | "githubUser": "izontm", 646 | "avatar": "https://avatars1.githubusercontent.com/u/860741?v=4", 647 | "total_pull_requests": 2, 648 | "approved": true 649 | }, 650 | { 651 | "githubID": "25023177", 652 | "githubUser": "cristiandean", 653 | "avatar": "https://avatars0.githubusercontent.com/u/25023177?v=4", 654 | "total_pull_requests": 2, 655 | "approved": true 656 | }, 657 | { 658 | "githubID": "12359941", 659 | "githubUser": "ivanch", 660 | "avatar": "https://avatars0.githubusercontent.com/u/12359941?v=4", 661 | "total_pull_requests": 2, 662 | "approved": true 663 | }, 664 | { 665 | "githubID": "18710260", 666 | "githubUser": "aguimaraesduarte", 667 | "avatar": "https://avatars0.githubusercontent.com/u/18710260?v=4", 668 | "total_pull_requests": 2, 669 | "approved": true 670 | }, 671 | { 672 | "githubID": "1333599", 673 | "githubUser": "arturfsousa", 674 | "avatar": "https://avatars0.githubusercontent.com/u/1333599?v=4", 675 | "total_pull_requests": 2, 676 | "approved": true 677 | }, 678 | { 679 | "githubID": "9121359", 680 | "githubUser": "lubien", 681 | "avatar": "https://avatars3.githubusercontent.com/u/9121359?v=4", 682 | "total_pull_requests": 2, 683 | "approved": true 684 | }, 685 | { 686 | "githubID": "86251", 687 | "githubUser": "ggarnier", 688 | "avatar": "https://avatars3.githubusercontent.com/u/86251?v=4", 689 | "total_pull_requests": 2, 690 | "approved": true 691 | }, 692 | { 693 | "githubID": "22118060", 694 | "githubUser": "LeonardoFurtado", 695 | "avatar": "https://avatars3.githubusercontent.com/u/22118060?v=4", 696 | "total_pull_requests": 2, 697 | "approved": true 698 | }, 699 | { 700 | "githubID": "3018196", 701 | "githubUser": "markosystem", 702 | "avatar": "https://avatars0.githubusercontent.com/u/3018196?v=4", 703 | "total_pull_requests": 2, 704 | "approved": true 705 | }, 706 | { 707 | "githubID": "26371672", 708 | "githubUser": "BruunoMM", 709 | "avatar": "https://avatars2.githubusercontent.com/u/26371672?v=4", 710 | "total_pull_requests": 2, 711 | "approved": true 712 | }, 713 | { 714 | "githubID": "40367872", 715 | "githubUser": "Krlier", 716 | "avatar": "https://avatars0.githubusercontent.com/u/40367872?v=4", 717 | "total_pull_requests": 2, 718 | "approved": true 719 | }, 720 | { 721 | "githubID": "9597125", 722 | "githubUser": "davidpvilaca", 723 | "avatar": "https://avatars3.githubusercontent.com/u/9597125?v=4", 724 | "total_pull_requests": 2, 725 | "approved": true 726 | }, 727 | { 728 | "githubID": "12446314", 729 | "githubUser": "alvesgabriel", 730 | "avatar": "https://avatars3.githubusercontent.com/u/12446314?v=4", 731 | "total_pull_requests": 2, 732 | "approved": true 733 | }, 734 | { 735 | "githubID": "16190825", 736 | "githubUser": "beescuit", 737 | "avatar": "https://avatars1.githubusercontent.com/u/16190825?v=4", 738 | "total_pull_requests": 2, 739 | "approved": true 740 | }, 741 | { 742 | "githubID": "39417", 743 | "githubUser": "thiagobfiorenza", 744 | "avatar": "https://avatars2.githubusercontent.com/u/39417?v=4", 745 | "total_pull_requests": 2, 746 | "approved": true 747 | }, 748 | { 749 | "githubID": "13144804", 750 | "githubUser": "alexandreyy", 751 | "avatar": "https://avatars1.githubusercontent.com/u/13144804?v=4", 752 | "total_pull_requests": 2, 753 | "approved": true 754 | }, 755 | { 756 | "githubID": "12671634", 757 | "githubUser": "eulercamposbarros", 758 | "avatar": "https://avatars2.githubusercontent.com/u/12671634?v=4", 759 | "total_pull_requests": 2, 760 | "approved": true 761 | }, 762 | { 763 | "githubID": "663286", 764 | "githubUser": "edgarberlinck", 765 | "avatar": "https://avatars1.githubusercontent.com/u/663286?v=4", 766 | "total_pull_requests": 2, 767 | "approved": true 768 | }, 769 | { 770 | "githubID": "6757777", 771 | "githubUser": "CoderSquirrel", 772 | "avatar": "https://avatars1.githubusercontent.com/u/6757777?v=4", 773 | "total_pull_requests": 2, 774 | "approved": true 775 | }, 776 | { 777 | "githubID": "32949153", 778 | "githubUser": "felipe-sbatista", 779 | "avatar": "https://avatars3.githubusercontent.com/u/32949153?v=4", 780 | "total_pull_requests": 2, 781 | "approved": true 782 | }, 783 | { 784 | "githubID": "19511732", 785 | "githubUser": "LiliGuimaraes", 786 | "avatar": "https://avatars3.githubusercontent.com/u/19511732?v=4", 787 | "total_pull_requests": 2, 788 | "approved": true 789 | }, 790 | { 791 | "githubID": "11020807", 792 | "githubUser": "endersonmenezes", 793 | "avatar": "https://avatars2.githubusercontent.com/u/11020807?v=4", 794 | "total_pull_requests": 2, 795 | "approved": true 796 | }, 797 | { 798 | "githubID": "1298871", 799 | "githubUser": "tclemos", 800 | "avatar": "https://avatars3.githubusercontent.com/u/1298871?v=4", 801 | "total_pull_requests": 2, 802 | "approved": true 803 | }, 804 | { 805 | "githubID": "15807921", 806 | "githubUser": "ThiagoWhispher", 807 | "avatar": "https://avatars0.githubusercontent.com/u/15807921?v=4", 808 | "total_pull_requests": 2, 809 | "approved": true 810 | }, 811 | { 812 | "githubID": "5731176", 813 | "githubUser": "TiagoDanin", 814 | "avatar": "https://avatars3.githubusercontent.com/u/5731176?v=4", 815 | "total_pull_requests": 2, 816 | "approved": true 817 | }, 818 | { 819 | "githubID": "25423500", 820 | "githubUser": "phakiller", 821 | "avatar": "https://avatars1.githubusercontent.com/u/25423500?v=4", 822 | "total_pull_requests": 2, 823 | "approved": true 824 | }, 825 | { 826 | "githubID": "1598854", 827 | "githubUser": "rafaelsq", 828 | "avatar": "https://avatars1.githubusercontent.com/u/1598854?v=4", 829 | "total_pull_requests": 2, 830 | "approved": true 831 | }, 832 | { 833 | "githubID": "40927839", 834 | "githubUser": "lucasferreiralimax", 835 | "avatar": "https://avatars2.githubusercontent.com/u/40927839?v=4", 836 | "total_pull_requests": 2, 837 | "approved": true 838 | }, 839 | { 840 | "githubID": "26823840", 841 | "githubUser": "victormazevedo", 842 | "avatar": "https://avatars0.githubusercontent.com/u/26823840?v=4", 843 | "total_pull_requests": 2, 844 | "approved": true 845 | }, 846 | { 847 | "githubID": "26108090", 848 | "githubUser": "wdsrocha", 849 | "avatar": "https://avatars3.githubusercontent.com/u/26108090?v=4", 850 | "total_pull_requests": 2, 851 | "approved": true 852 | }, 853 | { 854 | "githubID": "33805207", 855 | "githubUser": "IsraelSampaio", 856 | "avatar": "https://avatars0.githubusercontent.com/u/33805207?v=4", 857 | "total_pull_requests": 2, 858 | "approved": true 859 | }, 860 | { 861 | "githubID": "10249593", 862 | "githubUser": "rrrahal", 863 | "avatar": "https://avatars2.githubusercontent.com/u/10249593?v=4", 864 | "total_pull_requests": 2, 865 | "approved": true 866 | }, 867 | { 868 | "githubID": "31492173", 869 | "githubUser": "n8eloy", 870 | "avatar": "https://avatars0.githubusercontent.com/u/31492173?v=4", 871 | "total_pull_requests": 2, 872 | "approved": true 873 | }, 874 | { 875 | "githubID": "5223675", 876 | "githubUser": "cadu-goncalves", 877 | "avatar": "https://avatars3.githubusercontent.com/u/5223675?v=4", 878 | "total_pull_requests": 2, 879 | "approved": true 880 | }, 881 | { 882 | "githubID": "23244625", 883 | "githubUser": "vitor-fernandes", 884 | "avatar": "https://avatars0.githubusercontent.com/u/23244625?v=4", 885 | "total_pull_requests": 2, 886 | "approved": true 887 | }, 888 | { 889 | "githubID": "9432058", 890 | "githubUser": "marcjal", 891 | "avatar": "https://avatars2.githubusercontent.com/u/9432058?v=4", 892 | "total_pull_requests": 2, 893 | "approved": true 894 | }, 895 | { 896 | "githubID": "25045483", 897 | "githubUser": "garrettmasters", 898 | "avatar": "https://avatars3.githubusercontent.com/u/25045483?v=4", 899 | "total_pull_requests": 2, 900 | "approved": true 901 | }, 902 | { 903 | "githubID": "40031432", 904 | "githubUser": "JoseDavi", 905 | "avatar": "https://avatars1.githubusercontent.com/u/40031432?v=4", 906 | "total_pull_requests": 2, 907 | "approved": true 908 | }, 909 | { 910 | "githubID": "32279982", 911 | "githubUser": "ingridpacheco", 912 | "avatar": "https://avatars0.githubusercontent.com/u/32279982?v=4", 913 | "total_pull_requests": 2, 914 | "approved": true 915 | }, 916 | { 917 | "githubID": "34948516", 918 | "githubUser": "LuanaGP", 919 | "avatar": "https://avatars3.githubusercontent.com/u/34948516?v=4", 920 | "total_pull_requests": 2, 921 | "approved": true 922 | }, 923 | { 924 | "githubID": "36035548", 925 | "githubUser": "emanuel-gomes", 926 | "avatar": "https://avatars2.githubusercontent.com/u/36035548?v=4", 927 | "total_pull_requests": 2, 928 | "approved": false 929 | }, 930 | { 931 | "githubID": "44042977", 932 | "githubUser": "murilomattioli", 933 | "avatar": "https://avatars3.githubusercontent.com/u/44042977?v=4", 934 | "total_pull_requests": 2, 935 | "approved": false 936 | }, 937 | { 938 | "githubID": "31544944", 939 | "githubUser": "DinoSaulo", 940 | "avatar": "https://avatars3.githubusercontent.com/u/31544944?v=4", 941 | "total_pull_requests": 2, 942 | "approved": false 943 | }, 944 | { 945 | "githubID": "12217036", 946 | "githubUser": "grmano", 947 | "avatar": "https://avatars3.githubusercontent.com/u/12217036?v=4", 948 | "total_pull_requests": 2, 949 | "approved": false 950 | }, 951 | { 952 | "githubID": "29764688", 953 | "githubUser": "All3yp", 954 | "avatar": "https://avatars1.githubusercontent.com/u/29764688?v=4", 955 | "total_pull_requests": 2, 956 | "approved": false 957 | }, 958 | { 959 | "githubID": "23052132", 960 | "githubUser": "IvanArjona", 961 | "avatar": "https://avatars2.githubusercontent.com/u/23052132?v=4", 962 | "total_pull_requests": 2, 963 | "approved": false 964 | }, 965 | { 966 | "githubID": "50667733", 967 | "githubUser": "saaddalida", 968 | "avatar": "https://avatars0.githubusercontent.com/u/50667733?v=4", 969 | "total_pull_requests": 2, 970 | "approved": false 971 | }, 972 | { 973 | "githubID": "43557983", 974 | "githubUser": "Andre-rsfc", 975 | "avatar": "https://avatars2.githubusercontent.com/u/43557983?v=4", 976 | "total_pull_requests": 2, 977 | "approved": false 978 | }, 979 | { 980 | "githubID": "25347174", 981 | "githubUser": "bujiii", 982 | "avatar": "https://avatars3.githubusercontent.com/u/25347174?v=4", 983 | "total_pull_requests": 2, 984 | "approved": false 985 | }, 986 | { 987 | "githubID": "40612788", 988 | "githubUser": "davig-sousa", 989 | "avatar": "https://avatars0.githubusercontent.com/u/40612788?v=4", 990 | "total_pull_requests": 2, 991 | "approved": false 992 | }, 993 | { 994 | "githubID": "25506431", 995 | "githubUser": "amintasvrp", 996 | "avatar": "https://avatars3.githubusercontent.com/u/25506431?v=4", 997 | "total_pull_requests": 2, 998 | "approved": false 999 | }, 1000 | { 1001 | "githubID": "30505330", 1002 | "githubUser": "JohnVict0r", 1003 | "avatar": "https://avatars3.githubusercontent.com/u/30505330?v=4", 1004 | "total_pull_requests": 2, 1005 | "approved": false 1006 | }, 1007 | { 1008 | "githubID": "33194050", 1009 | "githubUser": "himanshu1root", 1010 | "avatar": "https://avatars1.githubusercontent.com/u/33194050?v=4", 1011 | "total_pull_requests": 2, 1012 | "approved": false 1013 | }, 1014 | { 1015 | "githubID": "6394262", 1016 | "githubUser": "luccamendonca", 1017 | "avatar": "https://avatars2.githubusercontent.com/u/6394262?v=4", 1018 | "total_pull_requests": 1, 1019 | "approved": false 1020 | }, 1021 | { 1022 | "githubID": "7342697", 1023 | "githubUser": "brenol", 1024 | "avatar": "https://avatars0.githubusercontent.com/u/7342697?v=4", 1025 | "total_pull_requests": 1, 1026 | "approved": false 1027 | }, 1028 | { 1029 | "githubID": "342161", 1030 | "githubUser": "mateuspontes", 1031 | "avatar": "https://avatars0.githubusercontent.com/u/342161?v=4", 1032 | "total_pull_requests": 1, 1033 | "approved": false 1034 | }, 1035 | { 1036 | "githubID": "29216027", 1037 | "githubUser": "marceloFA", 1038 | "avatar": "https://avatars0.githubusercontent.com/u/29216027?v=4", 1039 | "total_pull_requests": 1, 1040 | "approved": false 1041 | }, 1042 | { 1043 | "githubID": "20195874", 1044 | "githubUser": "danilogila", 1045 | "avatar": "https://avatars1.githubusercontent.com/u/20195874?v=4", 1046 | "total_pull_requests": 1, 1047 | "approved": false 1048 | }, 1049 | { 1050 | "githubID": "516453", 1051 | "githubUser": "renatoaquino", 1052 | "avatar": "https://avatars3.githubusercontent.com/u/516453?v=4", 1053 | "total_pull_requests": 1, 1054 | "approved": false 1055 | }, 1056 | { 1057 | "githubID": "27583162", 1058 | "githubUser": "luanraithz", 1059 | "avatar": "https://avatars2.githubusercontent.com/u/27583162?v=4", 1060 | "total_pull_requests": 1, 1061 | "approved": false 1062 | }, 1063 | { 1064 | "githubID": "18344707", 1065 | "githubUser": "BadduCoder", 1066 | "avatar": "https://avatars1.githubusercontent.com/u/18344707?v=4", 1067 | "total_pull_requests": 1, 1068 | "approved": false 1069 | }, 1070 | { 1071 | "githubID": "17203172", 1072 | "githubUser": "0x15F9", 1073 | "avatar": "https://avatars2.githubusercontent.com/u/17203172?v=4", 1074 | "total_pull_requests": 1, 1075 | "approved": false 1076 | }, 1077 | { 1078 | "githubID": "17353066", 1079 | "githubUser": "Marcuspo", 1080 | "avatar": "https://avatars2.githubusercontent.com/u/17353066?v=4", 1081 | "total_pull_requests": 1, 1082 | "approved": false 1083 | }, 1084 | { 1085 | "githubID": "32495998", 1086 | "githubUser": "treviza153", 1087 | "avatar": "https://avatars2.githubusercontent.com/u/32495998?v=4", 1088 | "total_pull_requests": 1, 1089 | "approved": false 1090 | }, 1091 | { 1092 | "githubID": "38537062", 1093 | "githubUser": "g-thome", 1094 | "avatar": "https://avatars0.githubusercontent.com/u/38537062?v=4", 1095 | "total_pull_requests": 1, 1096 | "approved": false 1097 | }, 1098 | { 1099 | "githubID": "43054051", 1100 | "githubUser": "tacoelho", 1101 | "avatar": "https://avatars0.githubusercontent.com/u/43054051?v=4", 1102 | "total_pull_requests": 1, 1103 | "approved": false 1104 | }, 1105 | { 1106 | "githubID": "22209724", 1107 | "githubUser": "LucianoHanna", 1108 | "avatar": "https://avatars1.githubusercontent.com/u/22209724?v=4", 1109 | "total_pull_requests": 1, 1110 | "approved": false 1111 | }, 1112 | { 1113 | "githubID": "44869983", 1114 | "githubUser": "limadiego", 1115 | "avatar": "https://avatars2.githubusercontent.com/u/44869983?v=4", 1116 | "total_pull_requests": 1, 1117 | "approved": false 1118 | }, 1119 | { 1120 | "githubID": "20875849", 1121 | "githubUser": "samisafatli", 1122 | "avatar": "https://avatars2.githubusercontent.com/u/20875849?v=4", 1123 | "total_pull_requests": 1, 1124 | "approved": false 1125 | }, 1126 | { 1127 | "githubID": "7906420", 1128 | "githubUser": "vanessasoutoc", 1129 | "avatar": "https://avatars1.githubusercontent.com/u/7906420?v=4", 1130 | "total_pull_requests": 1, 1131 | "approved": false 1132 | }, 1133 | { 1134 | "githubID": "17277588", 1135 | "githubUser": "lucassoares", 1136 | "avatar": "https://avatars2.githubusercontent.com/u/17277588?v=4", 1137 | "total_pull_requests": 1, 1138 | "approved": false 1139 | }, 1140 | { 1141 | "githubID": "12648924", 1142 | "githubUser": "mthbernardes", 1143 | "avatar": "https://avatars0.githubusercontent.com/u/12648924?v=4", 1144 | "total_pull_requests": 1, 1145 | "approved": false 1146 | }, 1147 | { 1148 | "githubID": "17506057", 1149 | "githubUser": "LuAnderson", 1150 | "avatar": "https://avatars0.githubusercontent.com/u/17506057?v=4", 1151 | "total_pull_requests": 1, 1152 | "approved": false 1153 | }, 1154 | { 1155 | "githubID": "10149871", 1156 | "githubUser": "matgomes", 1157 | "avatar": "https://avatars1.githubusercontent.com/u/10149871?v=4", 1158 | "total_pull_requests": 1, 1159 | "approved": false 1160 | }, 1161 | { 1162 | "githubID": "7130956", 1163 | "githubUser": "douglas-neves", 1164 | "avatar": "https://avatars3.githubusercontent.com/u/7130956?v=4", 1165 | "total_pull_requests": 1, 1166 | "approved": false 1167 | }, 1168 | { 1169 | "githubID": "13686332", 1170 | "githubUser": "gabrielreisn", 1171 | "avatar": "https://avatars1.githubusercontent.com/u/13686332?v=4", 1172 | "total_pull_requests": 1, 1173 | "approved": false 1174 | }, 1175 | { 1176 | "githubID": "3740437", 1177 | "githubUser": "tiao", 1178 | "avatar": "https://avatars2.githubusercontent.com/u/3740437?v=4", 1179 | "total_pull_requests": 1, 1180 | "approved": false 1181 | }, 1182 | { 1183 | "githubID": "3136012", 1184 | "githubUser": "GuyKh", 1185 | "avatar": "https://avatars3.githubusercontent.com/u/3136012?v=4", 1186 | "total_pull_requests": 1, 1187 | "approved": false 1188 | }, 1189 | { 1190 | "githubID": "36860521", 1191 | "githubUser": "i-mora", 1192 | "avatar": "https://avatars1.githubusercontent.com/u/36860521?v=4", 1193 | "total_pull_requests": 1, 1194 | "approved": false 1195 | }, 1196 | { 1197 | "githubID": "17456370", 1198 | "githubUser": "rohit223", 1199 | "avatar": "https://avatars3.githubusercontent.com/u/17456370?v=4", 1200 | "total_pull_requests": 1, 1201 | "approved": false 1202 | }, 1203 | { 1204 | "githubID": "13261860", 1205 | "githubUser": "osmarpetry", 1206 | "avatar": "https://avatars1.githubusercontent.com/u/13261860?v=4", 1207 | "total_pull_requests": 1, 1208 | "approved": false 1209 | }, 1210 | { 1211 | "githubID": "39953508", 1212 | "githubUser": "sachinshingade", 1213 | "avatar": "https://avatars1.githubusercontent.com/u/39953508?v=4", 1214 | "total_pull_requests": 1, 1215 | "approved": false 1216 | }, 1217 | { 1218 | "githubID": "24602363", 1219 | "githubUser": "luko0610", 1220 | "avatar": "https://avatars3.githubusercontent.com/u/24602363?v=4", 1221 | "total_pull_requests": 1, 1222 | "approved": false 1223 | }, 1224 | { 1225 | "githubID": "11477078", 1226 | "githubUser": "theajr", 1227 | "avatar": "https://avatars0.githubusercontent.com/u/11477078?v=4", 1228 | "total_pull_requests": 1, 1229 | "approved": false 1230 | }, 1231 | { 1232 | "githubID": "34301187", 1233 | "githubUser": "AyushBherwani1998", 1234 | "avatar": "https://avatars2.githubusercontent.com/u/34301187?v=4", 1235 | "total_pull_requests": 1, 1236 | "approved": false 1237 | }, 1238 | { 1239 | "githubID": "46511803", 1240 | "githubUser": "RishabMangal", 1241 | "avatar": "https://avatars2.githubusercontent.com/u/46511803?v=4", 1242 | "total_pull_requests": 1, 1243 | "approved": false 1244 | }, 1245 | { 1246 | "githubID": "16398237", 1247 | "githubUser": "parthendo", 1248 | "avatar": "https://avatars2.githubusercontent.com/u/16398237?v=4", 1249 | "total_pull_requests": 1, 1250 | "approved": false 1251 | }, 1252 | { 1253 | "githubID": "42267022", 1254 | "githubUser": "hv-ojha", 1255 | "avatar": "https://avatars3.githubusercontent.com/u/42267022?v=4", 1256 | "total_pull_requests": 1, 1257 | "approved": false 1258 | }, 1259 | { 1260 | "githubID": "14948182", 1261 | "githubUser": "v0idpwn", 1262 | "avatar": "https://avatars3.githubusercontent.com/u/14948182?v=4", 1263 | "total_pull_requests": 1, 1264 | "approved": false 1265 | } 1266 | ] 1267 | } 1268 | } 1269 | --------------------------------------------------------------------------------