├── .eslintrc ├── .gitignore ├── .osfg-dir-config.js ├── .setup-symlinks.sh ├── LICENSE.md ├── README.md ├── docs ├── asset-manifest.json ├── conference-for-good │ └── index.html ├── favicon.ico ├── index.html ├── league-for-good │ └── index.html ├── mail-for-good │ └── index.html ├── manifest.json ├── meeting-for-good │ └── index.html ├── nonprofits.css ├── open-source-for-good-directory │ └── index.html ├── pantry-for-good │ └── index.html └── static │ ├── css │ ├── main.0515109c.css │ └── main.0515109c.css.map │ └── js │ ├── main.d4eb4b9c.js │ └── main.d4eb4b9c.js.map ├── package.json ├── public ├── conference-for-good ├── favicon.ico ├── index.html ├── league-for-good ├── mail-for-good ├── manifest.json ├── meeting-for-good ├── nonprofits.css ├── open-source-for-good-directory └── pantry-for-good ├── repo-list.json ├── src ├── actions │ └── index.js ├── assets │ └── fcc-logo-white.png ├── components │ ├── Card.js │ ├── Header.js │ ├── Main.js │ ├── Search.js │ ├── SortMenu.js │ ├── Testimonial.js │ └── Title.js ├── containers │ └── App.js ├── helpers │ └── index.js ├── index.css ├── index.js └── reducers │ └── index.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app", 3 | "parserOption": { 4 | "ecmaVersion": 6, 5 | "ecmaFeatures": { 6 | "jsx": true 7 | } 8 | }, 9 | "env": { 10 | "es6": true, 11 | "browser": true, 12 | "mocha": true, 13 | "node": true 14 | }, 15 | "parser": "babel-eslint", 16 | "plugins": [ 17 | "react", 18 | "import", 19 | "prefer-object-spread" 20 | ], 21 | "settings": { 22 | "import/ignore": [ 23 | "node_modules", 24 | "\\.json$" 25 | ], 26 | "import/extensions": [ 27 | ".js", 28 | ".jsx" 29 | ] 30 | }, 31 | "globals": { 32 | "Promise": true, 33 | "window": true, 34 | "$": true, 35 | "ga": true, 36 | "jQuery": true, 37 | "router": true 38 | }, 39 | "rules": { 40 | "block-scoped-var": 0, 41 | "brace-style": [ 2, "1tbs", { "allowSingleLine": true } ], 42 | "camelcase": 2, 43 | "comma-dangle": 2, 44 | "comma-spacing": [ 2, { "before": false, "after": true } ], 45 | "comma-style": [ 2, "last" ], 46 | "complexity": 0, 47 | "consistent-return": 2, 48 | "consistent-this": 0, 49 | "curly": 2, 50 | "default-case": 2, 51 | "dot-notation": 0, 52 | "eol-last": 2, 53 | "eqeqeq": 2, 54 | "func-names": 0, 55 | "func-style": 0, 56 | "guard-for-in": 2, 57 | "handle-callback-err": 2, 58 | "jsx-quotes": [ 2, "prefer-single" ], 59 | "key-spacing": [ 2, { "beforeColon": false, "afterColon": true } ], 60 | "keyword-spacing": [ 2 ], 61 | "max-depth": 0, 62 | "max-len": [ 2, 80, 2 ], 63 | "max-nested-callbacks": 0, 64 | "max-params": 0, 65 | "max-statements": 0, 66 | "new-cap": 0, 67 | "new-parens": 2, 68 | "no-alert": 2, 69 | "no-array-constructor": 2, 70 | "no-bitwise": 2, 71 | "no-caller": 2, 72 | "no-catch-shadow": 2, 73 | "no-cond-assign": 2, 74 | "no-console": 0, 75 | "no-constant-condition": 2, 76 | "no-control-regex": 2, 77 | "no-debugger": 2, 78 | "no-delete-var": 2, 79 | "no-div-regex": 2, 80 | "no-dupe-keys": 2, 81 | "no-else-return": 0, 82 | "no-empty": 2, 83 | "no-empty-character-class": 2, 84 | "no-eq-null": 2, 85 | "no-eval": 2, 86 | "no-ex-assign": 2, 87 | "no-extend-native": 2, 88 | "no-extra-bind": 2, 89 | "no-extra-boolean-cast": 2, 90 | "no-extra-parens": 0, 91 | "no-extra-semi": 2, 92 | "no-fallthrough": 2, 93 | "no-floating-decimal": 2, 94 | "no-func-assign": 2, 95 | "no-implied-eval": 2, 96 | "no-inline-comments": 2, 97 | "no-inner-declarations": 2, 98 | "no-invalid-regexp": 2, 99 | "no-irregular-whitespace": 2, 100 | "no-iterator": 2, 101 | "no-label-var": 2, 102 | "no-labels": 2, 103 | "no-lone-blocks": 2, 104 | "no-lonely-if": 2, 105 | "no-loop-func": 2, 106 | "no-mixed-requires": 0, 107 | "no-mixed-spaces-and-tabs": 2, 108 | "no-multi-spaces": 2, 109 | "no-multi-str": 2, 110 | "no-multiple-empty-lines": [ 2, { "max": 2 } ], 111 | "no-native-reassign": 2, 112 | "no-negated-in-lhs": 2, 113 | "no-nested-ternary": 2, 114 | "no-new": 2, 115 | "no-new-func": 2, 116 | "no-new-object": 2, 117 | "no-new-require": 2, 118 | "no-new-wrappers": 2, 119 | "no-obj-calls": 2, 120 | "no-octal": 2, 121 | "no-octal-escape": 2, 122 | "no-path-concat": 2, 123 | "no-plusplus": 0, 124 | "no-process-env": 0, 125 | "no-process-exit": 2, 126 | "no-proto": 2, 127 | "no-redeclare": 2, 128 | "no-regex-spaces": 2, 129 | "no-reserved-keys": 0, 130 | "no-restricted-modules": 0, 131 | "no-return-assign": 2, 132 | "no-script-url": 2, 133 | "no-self-compare": 2, 134 | "no-sequences": 2, 135 | "no-shadow": 0, 136 | "no-shadow-restricted-names": 2, 137 | "no-spaced-func": 2, 138 | "no-sparse-arrays": 2, 139 | "no-sync": 0, 140 | "no-ternary": 0, 141 | "no-trailing-spaces": 2, 142 | "no-undef": 2, 143 | "no-undef-init": 2, 144 | "no-undefined": 2, 145 | "no-underscore-dangle": 0, 146 | "no-unreachable": 2, 147 | "no-unused-expressions": 2, 148 | "no-unused-vars": 2, 149 | "no-use-before-define": 0, 150 | "no-void": 0, 151 | "no-warning-comments": [ 2, { "terms": [ "fixme" ], "location": "start" } ], 152 | "no-with": 2, 153 | "one-var": 0, 154 | "operator-assignment": 0, 155 | "padded-blocks": 0, 156 | "quote-props": [ 2, "as-needed" ], 157 | "quotes": [ 2, "single", "avoid-escape" ], 158 | "radix": 2, 159 | "semi": [ 2, "always" ], 160 | "semi-spacing": [ 2, { "before": false, "after": true } ], 161 | "sort-vars": 0, 162 | "space-before-blocks": [ 2, "always" ], 163 | "space-before-function-paren": [ 2, "never" ], 164 | "space-in-brackets": 0, 165 | "space-in-parens": 0, 166 | "space-infix-ops": 2, 167 | "space-unary-ops": [ 2, { "words": true, "nonwords": false } ], 168 | "spaced-comment": [ 2, "always", { "exceptions": [ "-" ] } ], 169 | "strict": 0, 170 | "use-isnan": 2, 171 | "valid-jsdoc": 2, 172 | "valid-typeof": 2, 173 | "vars-on-top": 0, 174 | "wrap-iife": [ 2, "any" ], 175 | "wrap-regex": 2, 176 | "yoda": 0, 177 | 178 | "react/display-name": 2, 179 | "react/jsx-boolean-value": [ 2, "always" ], 180 | "react/jsx-closing-bracket-location": [ 2, { "selfClosing": "line-aligned", "nonEmpty": "props-aligned" } ], 181 | "react/jsx-no-undef": 2, 182 | "react/jsx-sort-props": [ 2, { "ignoreCase": true } ], 183 | "react/jsx-uses-react": 2, 184 | "react/jsx-uses-vars": 2, 185 | "react/jsx-wrap-multilines": 2, 186 | "react/no-did-mount-set-state": 2, 187 | "react/no-did-update-set-state": 2, 188 | "react/no-multi-comp": [ 2, { "ignoreStateless": true } ], 189 | "react/no-unknown-property": 2, 190 | "react/prop-types": 2, 191 | "react/react-in-jsx-scope": 2, 192 | "react/self-closing-comp": 2, 193 | "react/sort-prop-types": 2, 194 | 195 | "import/default": 2, 196 | "import/export": 2, 197 | "import/extensions": [ 0, "always" ], 198 | "import/first": 2, 199 | "import/named": 2, 200 | "import/namespace": 2, 201 | "import/newline-after-import": 2, 202 | "import/no-duplicates": 2, 203 | "import/no-unresolved": 2, 204 | "import/unambiguous": 2, 205 | 206 | "prefer-object-spread/prefer-object-spread": 2 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Webpack build 40 | build 41 | 42 | # Jekyll build files 43 | *.gem 44 | docs/_site 45 | docs/.sass-cache 46 | docs/bundle 47 | docs/vendor 48 | 49 | # macOS store 50 | .DS_Store 51 | 52 | # VS Code Configuration files 53 | .vscode/ 54 | 55 | # .env Confi Files 56 | .env 57 | 58 | # Create React App Build folder 59 | build 60 | 61 | -------------------------------------------------------------------------------- /.osfg-dir-config.js: -------------------------------------------------------------------------------- 1 | /* 2 | OPEN SOURCE FOR GOOD DIRECTORY SAMPLE CONFIG FILE 3 | 4 | title: Displayed at the top and as the webpage title 5 | demoVideo: the YouTube video address 6 | liveDemo: the address of the project's homepage 7 | description: an ES6 template string that contains GitHub-flavored Markdown. 8 | Keep this relatively short - a paragraph tops 9 | body: an ES6 template string with GitHub-flavored Markdown. 10 | Please include the open source license, with the freeCodeCamp copyright at the end. 11 | 12 | If the 'liveDemo' or the 'demoVideo' aren't yet available, you can exclued them. 13 | They just won't be added to the project's page. 14 | */ 15 | 16 | module.exports = { 17 | title: 'Mail for Good', 18 | demoVideo: 'https://www.youtube.com/watch?v=_7U03GVD4a8', 19 | liveDemo: 'https://meeting.freecodecamp.com/', 20 | description: `An app for sending millions of emails as cheaply as possible. Mail for Good uses AWS Simple Email Service to send bulk emails at $0.10 per 1000 emails. 21 | 22 | Mail for Good is fast and memory efficient, currently sending over 100 emails per second on a 1gb Digital Ocean VPS. 23 | 24 | We've used Mail for Good to deliver newsletters to hundreds of thousands of campers per week. 25 | `, 26 | body: `## What does Mail for Good do? 27 | 28 | With Mail for Good you can: 29 | 30 | - Send email campaigns of unlimited size. 31 | - Import emails saved in CSV format. 32 | - Create templates to reuse for convenience when sending email campaigns. 33 | - Track bounce rate and other standard metrics. You can also insert tracking pixels and unsubcribe links a click of a button. 34 | - Add custom fields to imported email lists such as names or cities. 35 | - Grant other users (limited or otherwise) permissions to use your account on your behalf. 36 | - Add embedded HTML newsletter sign up forms to your site. These are snippets of code that will let your users sign up with you at the click of a button. 37 | 38 | ### Performance 39 | 40 | We're currently sending weekly email blasts of over 700,000 emails in 3-4 hours on a $10 per month Digital Ocean VPS with 1gb memory and 1 core processor. 41 | 42 | Mail for Good is fast and scales to the rate limit enforced by AWS. 43 | 44 | ### Why are we doing this? 45 | 46 | We want to help nonprofits manage their email campaigns as inexpensively as possible, and have full control over their data. 47 | 48 | 49 | ### License 50 | 51 | This computer software is licensed under the Open Source [BSD-3-Clause](https://github.com/freeCodeCamp/Mail-for-Good/blob/master/LICENSE.md). 52 | 53 | Copyright (c) 2017, freeCodeCamp. 54 | ` 55 | }; 56 | -------------------------------------------------------------------------------- /.setup-symlinks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script for creating Symlinks inside the "public/" folder 4 | # that point to versions inside the "docs/" folder. This 5 | # process is done to enable the NonProfit view during development. 6 | # Only works for Unix like systems (MacOS, Linux). 7 | 8 | # Deleting Old Symlinks inside public 9 | cd public 10 | for f in *; do 11 | if [[ -L "$f" ]]; then 12 | rm $f 13 | echo "Deleted $f old Symlink file" 14 | fi 15 | done 16 | 17 | # Creating the New Symlinks 18 | for f in ../docs/*; do 19 | if [[ -d $f && $f != "../docs/static" && ! -L "$f" ]]; then 20 | ln -s $f . 21 | echo "Created new ${f: 8} Symlink file" 22 | fi 23 | done 24 | 25 | cd .. 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, freeCodeCamp 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Source for Good Directory 2 | 3 | A directory for freeCodeCamp's Open Source for Good Apps - Solutions for Nonprofits. 4 | 5 | ## Instructions for adding a Non-Profit Project 6 | 7 | There are two steps to add an Open Source for Good Project to the directory: 8 | 9 | 1. Add the file `.osfg-dir-config.js` to the **root of the Project**. 10 | * This will trigger an automatic build of the Project's page inside the directory. 11 | * Please **verify** that an **update** by CamperBot to `docs/[project-name]` has occurred in the master branch of the directory. 12 | * Fields: 13 | * **title:** Displayed at the top and as the webpage title 14 | * **demoVideo:** the YouTube video address 15 | * **liveDemo:** the address of the project's homepage 16 | * **description:** an ES6 template string that contains GitHub-flavored Markdown. Keep this relatively short - a paragraph tops. 17 | * **body:** an ES6 template string with GitHub-flavored Markdown. Please include the open source license, with the freeCodeCamp copyright at the end. 18 | * If the `liveDemo` or the `demoVideo` aren't yet available, you can exclued them. They just won't be added to the project's page. 19 | 20 | * You can see a [**sample config file**](https://github.com/freeCodeCamp/open-source-for-good-directory/blob/master/.osfg-dir-config.js) at the root of this repository. 21 | 22 | 2. Edit the file `repo-list.json` at the root of the directory to include the project. 23 | * This file will tell the directory app to fetch the corresponding GitHub data and include a card for the project. 24 | * If you don't yet have permissions to update this repo, please **request the edit** from one of the project's maintainers. 25 | * Instructions for the file: 26 | * Please keep this file **alphabetically sorted** by repo name 27 | * **Everything** should be in **lower case**. This is critical to our search functionality 28 | * **name:** the GitHub repo's name in lower case (without the preceeding freecodecamp/) 29 | * **icon:** the Image to be displayed in the project's card. This string contains a 30 | [Font Awesome icon HTML class](http://fontawesome.io/icons/). 31 | * **tags:** tags will be visible to users who aren't authenticated (we assume these users are people at nonprofits) 32 | * **status:** choose between `'dev'` and `'prod'`. Projects in `'dev'` won't be displayed to nonprofits (unauthenticated users). 33 | 34 | Please be paitient and while GitHub updates the directory - it will take a few minutes before the changes are reflected. 35 | 36 | 37 | ## Installation 38 | 39 | Make sure you have installed a recent version of [NodeJS](https://nodejs.org/) and **npm**. 40 | 41 | Open the folder you wish to install the project in using your terminal, and run: 42 | 43 | `git clone https://github.com/freeCodeCamp/open-source-for-good-directory` 44 | 45 | `cd` into the `open-source-for-good-directory` project that command created, then run `npm i` to install all the project dependencies. 46 | 47 | You'll need symbolic links inside the `public` folder that point to the corresponding `docs/[project-name]` directory. The bash script in the root of this repo. We've created a script to automate this process. Make sure the script is executable by running: `chmod +x .setup-symlinks.sh`. Then run `./.setup-symlinks.sh`. 48 | 49 | For Windows users wanting to use the script, you'll probably need the [Linux Subsystem](https://msdn.microsoft.com/en-us/commandline/wsl/about). We haven't tested this, so if you get this working, let us know how you did so, and we can add those steps to this guide. 50 | 51 | This directory is built using [Create React App](https://github.com/facebookincubator/create-react-app), so you can look for more info there if you run into trouble. 52 | 53 | To deploy the directory, run `yarn build` or `npm run build`. Then commit the changes to Github. 54 | 55 | ## Server 56 | The directory depends on a remote server to perform an automated webpage build for each project that requires it. The server works in the following way: 57 | 58 | 1. A Github WebHook registers push events for all the freeCodeCamp repos. It sends a POST request (URL/event) to a server hosted in Glitch.com (Specified on the WebHook configuration) 59 | 1. If there is an update to the configuration file `.osfg-dir-config.js`, it downloads the file and builds an HTML file. 60 | 1. The file is pushed to **this repo** inside the `docs` folder. 61 | 1. Everything inside the `docs` folder is automatically deployed to GitHub Pages, which in turn are linked to the directory's website. 62 | 63 | You can find the code for the server in [this repository](https://github.com/freeCodeCamp/osfg-dir-server) 64 | 65 | ### License 66 | 67 | This computer software is licensed under the open source [BSD-3-Clause](https://github.com/freeCodeCamp/open-source-for-good-directory/blob/master/LICENSE.md). 68 | 69 | Copyright (c) 2017, [freeCodeCamp](https://www.freecodecamp.org). 70 | -------------------------------------------------------------------------------- /docs/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "static/css/main.0515109c.css", 3 | "main.css.map": "static/css/main.0515109c.css.map", 4 | "main.js": "static/js/main.d4eb4b9c.js", 5 | "main.js.map": "static/js/main.d4eb4b9c.js.map" 6 | } -------------------------------------------------------------------------------- /docs/conference-for-good/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Conference for Good 12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 |

Conference for Good

23 |
24 |

An open source conference management tool. Schedule speakers and workshops, accept speaking proposals, and schedule timeslots.

25 |
26 |
27 |
28 | 29 |
30 |
31 | 39 |
40 |

License

41 |

This computer software is licensed under the Open Source BSD-3-Clause.

42 |

Copyright (c) 2017, freeCodeCamp.

43 |
44 |

Contributors

45 |
46 | 47 |
48 | 49 | 50 | 51 |
52 |
53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 |
67 |
68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 |
77 |
78 | 79 | 80 | 81 |
82 |
83 |
84 |
85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeCodeCamp/open-source-for-good-directory/821b3372d06bbf1798a2896d855d2d7b9871f489/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | Open Source for Good
-------------------------------------------------------------------------------- /docs/league-for-good/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | League for Good 12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 |

League for Good

23 |
24 |

This is a free, open-source web application designed to help sports leagues track their player and team stats, and simplify the other day-to-day tasks involved with team management. It was designed to accommodate many popular sports.

25 |
26 | 27 | 35 |
36 |

What does League for Good do?

37 |

Performance

38 |

Why are we doing this?

39 |

We want to help nonprofits manage their email campaigns as inexpensively as possible, and have full control over their data.

40 |

License

41 |

This computer software is licensed under the Open Source BSD-3-Clause.

42 |

Copyright (c) 2017, freeCodeCamp.

43 |
44 |

Contributors

45 |
46 | 47 |
48 | 49 | 50 | 51 |
52 |
53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 |
67 |
68 | 69 | 70 | 71 |
72 |
73 |
74 |
75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/mail-for-good/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | Mail for Good 11 |
12 | 13 | 14 |
15 | 16 |
17 | 18 |
19 |
20 |
21 |

Mail for Good

22 |
23 |

An app for sending millions of emails as cheaply as possible. Mail for Good uses AWS Simple Email Service to send bulk emails at $0.10 per 1000 emails.

24 |

Mail for Good is fast and memory efficient, currently sending over 100 emails per second on a 1gb Digital Ocean VPS.

25 |

We've used Mail for Good to deliver newsletters to hundreds of thousands of campers per week.

26 |
27 |
28 |
29 | 30 |
31 |
32 | 40 |
41 |

What does Mail for Good do?

42 |

With Mail for Good you can:

43 |
    44 |
  • Send email campaigns of unlimited size.
  • 45 |
  • Import emails that are saved in CSV format.
  • 46 |
  • Create templates to reuse for convenience when sending email campaigns.
  • 47 |
  • Track bounce rate and other standard metrics. You can also insert tracking pixels and unsubcribe links a click of a button.
  • 48 |
  • Add custom fields to imported email lists such as names or cities.
  • 49 |
  • Grant other users (limited or otherwise) permissions to use your account on your behalf.
  • 50 |
  • Add embedded HTML newsletter sign up forms to your site. These are snippets of code that will let your users sign up with you at the click of a button.
  • 51 |
52 |

Performance

53 |

We're currently sending weekly email blasts of over 700,000 emails in 3-4 hours on a $10 per month Digital Ocean VPS with 1gb memory and 1 core processor.

54 |

Mail for Good is fast and scales to the rate limit enforced by AWS.

55 |

Why are we doing this?

56 |

We want to help nonprofits manage their email campaigns as inexpensively as possible, and have full control over their data.

57 |

License

58 |

This computer software is licensed under the Open Source BSD-3-Clause.

59 |

Copyright (c) 2017, freeCodeCamp.

60 |
61 |

Contributors

62 |
63 | 64 |
65 | 66 | 67 | 68 |
69 |
70 | 71 | 72 | 73 |
74 |
75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 86 | 87 | 88 |
89 |
90 | 91 | 92 | 93 |
94 |
95 | 96 | 97 | 98 |
99 |
100 | 101 | 102 | 103 |
104 |
105 | 106 | 107 | 108 |
109 |
110 | 111 | 112 | 113 |
114 |
115 | 116 | 117 | 118 |
119 |
120 | 121 | 122 | 123 |
124 |
125 | 126 | 127 | 128 |
129 |
130 | 131 | 132 | 133 |
134 |
135 | 136 | 137 | 138 |
139 |
140 | 141 | 142 | 143 |
144 |
145 | 146 | 147 | 148 |
149 |
150 |
151 |
152 | 153 | 154 | -------------------------------------------------------------------------------- /docs/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "OSFG Directory", 3 | "name": "Open Source for Good Directory", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /docs/meeting-for-good/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Meeting for Good 12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 |

Meeting for Good

23 |
24 |

A tool to effortlessly schedule calls and meetings across multiple timezones.

25 |
26 |
27 |
28 | 29 |
30 |
31 | 43 |
44 |

License

45 |

This computer software is licensed under the Open Source BSD-3-Clause.

46 |

Copyright (c) 2017, freeCodeCamp.

47 |
48 |

Contributors

49 |
50 | 51 |
52 | 53 | 54 | 55 |
56 |
57 | 58 | 59 | 60 |
61 |
62 | 63 | 64 | 65 |
66 |
67 | 68 | 69 | 70 |
71 |
72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 |
81 |
82 | 83 | 84 | 85 |
86 |
87 | 88 | 89 | 90 |
91 |
92 | 93 | 94 | 95 |
96 |
97 | 98 | 99 | 100 |
101 |
102 | 103 | 104 | 105 |
106 |
107 | 108 | 109 | 110 |
111 |
112 | 113 | 114 | 115 |
116 |
117 |
118 |
119 | 120 | 121 | -------------------------------------------------------------------------------- /docs/nonprofits.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | font-family: 'Lato', sans-serif; 7 | font-size: 1.1em; 8 | font-weight: 300; 9 | 10 | margin: 0; 11 | padding: 0; 12 | 13 | letter-spacing: 0.03em; 14 | 15 | color: #212121; 16 | background-color: #e0e0e0; 17 | } 18 | 19 | .wrapper { 20 | display: flex; 21 | flex-direction: column; 22 | 23 | border-width: 1em 0 0 0; 24 | border-style: solid; 25 | border-color: #006400; 26 | 27 | align-items: center; 28 | justify-content: center; 29 | } 30 | 31 | .fcc-banner { 32 | display: flex; 33 | 34 | padding: 2em 0; 35 | 36 | align-items: center; 37 | justify-content: center; 38 | } 39 | 40 | .fcc-banner > img { 41 | display: block; 42 | 43 | width: 30vw; 44 | min-width: 310px; 45 | } 46 | 47 | .content-container { 48 | width: 48em; 49 | margin: 0 auto 4em; 50 | 51 | border: 1px solid #adadad; 52 | border-radius: 8px; 53 | background-color: #fff; 54 | } 55 | 56 | .content-container > * { 57 | padding: 0 3em; 58 | } 59 | 60 | .repo-name { 61 | font-weight: 400; 62 | 63 | margin: 0; 64 | padding: 0.75em; 65 | 66 | text-align: center; 67 | 68 | color: #fff; 69 | border-width: 1px; 70 | border-style: solid; 71 | border-color: #006400; 72 | border-radius: 8px 8px 0 0; 73 | background-color: #006400; 74 | } 75 | 76 | .content-container h1 { 77 | margin: 0; 78 | padding: 0.5em 0; 79 | 80 | text-align: center; 81 | 82 | border-bottom: 1px solid #e0e0e0; 83 | } 84 | 85 | .content-container h2 { 86 | margin: 0; 87 | padding: 0.5em 0; 88 | 89 | text-align: center; 90 | 91 | border-bottom: 1px solid #e0e0e0; 92 | } 93 | 94 | .content-container h3 { 95 | margin: 0; 96 | padding: 1em 0; 97 | 98 | text-align: center; 99 | } 100 | 101 | .content-container ul { 102 | margin-left: 1em; 103 | } 104 | 105 | .content-container img { 106 | max-width: 100%; 107 | 108 | border-radius: 4px; 109 | } 110 | 111 | .content-container li { 112 | margin: 1em 0; 113 | } 114 | 115 | .content-container code { 116 | padding: 0.5em 1em; 117 | 118 | border-radius: 3px; 119 | background-color: #fafafa; 120 | } 121 | 122 | .project-description { 123 | font-size: 1.1em; 124 | 125 | padding-top: 30px; 126 | padding-bottom: 20px; 127 | } 128 | 129 | .project-video { 130 | max-width: 100%; 131 | margin: 40px 0; 132 | } 133 | 134 | .video-container { 135 | position: relative;overflow: hidden;height: 0; 136 | padding-bottom: 56.25%; 137 | 138 | border: 1px solid black; 139 | } 140 | 141 | .video-container iframe, 142 | .video-container object, 143 | .video-container embed { 144 | position: absolute; 145 | top: 0; 146 | left: 0; 147 | 148 | width: 100%; 149 | height: 100%; 150 | } 151 | 152 | .buttons-container { 153 | display: flex; 154 | 155 | padding: 40px 0; 156 | 157 | align-items: center; 158 | flex-wrap: wrap; 159 | justify-content: center; 160 | } 161 | 162 | button { 163 | font-size: 1.3em; 164 | font-weight: 400; 165 | line-height: 1.42857143; 166 | 167 | min-width: 190px; 168 | margin: 10px 10px; 169 | padding: 12px 20px; 170 | 171 | cursor: pointer; 172 | user-select: none; 173 | transition: background 0.2s ease-in-out, border 0.2s ease-in-out; 174 | text-align: center; 175 | vertical-align: middle; 176 | 177 | color: #292f33; 178 | border: 1px solid #f1a02a; 179 | border-radius: 4px; 180 | outline: 0; 181 | background-color: #ffac33; 182 | background-image: linear-gradient(#ffcc4d, #ffac33); 183 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 184 | } 185 | 186 | button:hover { 187 | border-color: #ec8b11; 188 | background-color: #e99110; 189 | background-image: linear-gradient(#ffcc4d, #e99110); 190 | } 191 | 192 | .body-container { 193 | padding: 40px 3em; 194 | } 195 | 196 | .contributors { 197 | display: flex; 198 | 199 | padding: 1em 3em; 200 | 201 | flex-wrap: wrap; 202 | justify-content: center; 203 | } 204 | 205 | .contributor img { 206 | position: relative; 207 | z-index: 10; 208 | 209 | width: 3.5em; 210 | height: 3.5em; 211 | margin: 3px; 212 | 213 | border-radius: 50%; 214 | } 215 | 216 | @media (max-width: 860px) { 217 | .content-container, 218 | .contributors, 219 | .contributors { 220 | width: 90vw; 221 | } 222 | } 223 | 224 | @media (max-width: 720px) { 225 | .content-container, 226 | .contributors { 227 | width: 30em; 228 | padding: 0; 229 | } 230 | .contributors { 231 | padding: 2em; 232 | } 233 | } 234 | 235 | @media (max-width: 550px) { 236 | .content-container, 237 | .contributors { 238 | width: 95vw; 239 | margin: 0; 240 | padding: 0; 241 | } 242 | .contributors { 243 | padding: 1em; 244 | } 245 | .project-description, 246 | .body-container { 247 | padding: 1em; 248 | } 249 | .project-video { 250 | min-width: 300px; 251 | margin: 25px 0; 252 | padding: 10px; 253 | } 254 | } 255 | 256 | -------------------------------------------------------------------------------- /docs/open-source-for-good-directory/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Mail for Good 12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 |

Mail for Good

23 |
24 |

An app for sending millions of emails as cheaply as possible. Mail for Good uses AWS Simple Email Service to send bulk emails at $0.10 per 1000 emails.

25 |

Mail for Good is fast and memory efficient, currently sending over 100 emails per second on a 1gb Digital Ocean VPS.

26 |

We've used Mail for Good to deliver newsletters to hundreds of thousands of campers per week.

27 |
28 |
29 |
30 | 31 |
32 |
33 | 45 |
46 |

What does Mail for Good do?

47 |

With Mail for Good you can:

48 |
    49 |
  • Send email campaigns of unlimited size.
  • 50 |
  • Import emails saved in CSV format.
  • 51 |
  • Create templates to reuse for convenience when sending email campaigns.
  • 52 |
  • Track bounce rate and other standard metrics. You can also insert tracking pixels and unsubcribe links a click of a button.
  • 53 |
  • Add custom fields to imported email lists such as names or cities.
  • 54 |
  • Grant other users (limited or otherwise) permissions to use your account on your behalf.
  • 55 |
  • Add embedded HTML newsletter sign up forms to your site. These are snippets of code that will let your users sign up with you at the click of a button.
  • 56 |
57 |

Performance

58 |

We're currently sending weekly email blasts of over 700,000 emails in 3-4 hours on a $10 per month Digital Ocean VPS with 1gb memory and 1 core processor.

59 |

Mail for Good is fast and scales to the rate limit enforced by AWS.

60 |

Why are we doing this?

61 |

We want to help nonprofits manage their email campaigns as inexpensively as possible, and have full control over their data.

62 |

License

63 |

This computer software is licensed under the Open Source BSD-3-Clause.

64 |

Copyright (c) 2017, freeCodeCamp.

65 |
66 |

Contributors

67 |
68 | 69 |
70 | 71 | 72 | 73 |
74 |
75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 86 | 87 | 88 |
89 |
90 | 91 | 92 | 93 |
94 |
95 |
96 |
97 | 98 | 99 | -------------------------------------------------------------------------------- /docs/pantry-for-good/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pantry for Good 12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 |

Pantry for Good

23 |
24 |

An open source food bank logistics and food inventory management tool

25 |
26 | 27 | 39 |
40 |

License

41 |

This computer software is licensed under the Open Source BSD-3-Clause.

42 |

Copyright (c) 2017, freeCodeCamp.

43 |
44 |

Contributors

45 |
46 | 47 |
48 | 49 | 50 | 51 |
52 |
53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 |
67 |
68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 |
77 |
78 | 79 | 80 | 81 |
82 |
83 | 84 | 85 | 86 |
87 |
88 | 89 | 90 | 91 |
92 |
93 | 94 | 95 | 96 |
97 |
98 | 99 | 100 | 101 |
102 |
103 | 104 | 105 | 106 |
107 |
108 | 109 | 110 | 111 |
112 |
113 |
114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /docs/static/css/main.0515109c.css: -------------------------------------------------------------------------------- 1 | *{-webkit-box-sizing:border-box;box-sizing:border-box;text-rendering:optimizeLegibility;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{font-family:Lato,sans-serif;font-size:1.1em;font-weight:300;margin:0;padding:0;color:#2a2a2a}.app{min-height:100vh}.header{height:50px;padding:0 15px 0 35px;color:#fff;background-color:#006400}.header,.header-brand{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.header-brand{text-decoration:none}.header-brand>img{height:35px}.header-logo{color:#fff}.header-links{-ms-flex:4 1 0%;flex:4 1 0%;height:100%;margin:0;padding:0;list-style:none;color:#eee;-ms-flex-pack:end;justify-content:flex-end}.header-links,.header-links>li>a{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.header-links>li>a{font-size:1.1em;font-weight:600;height:inherit;padding:15px;padding-bottom:12px;cursor:pointer;text-decoration:none;color:inherit}#header-camper{font-size:1.35em;height:inherit}#header-camper>a{cursor:default}.header-links>li>a:hover{color:#006400;background-color:#eee}#donate-icon{display:none}.main{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;-ms-flex:1 1 0%;flex:1 1 0%;margin-top:1em}.main-title{font-size:2.2em;margin-top:1.5em;text-align:center}.main-desc{font-size:1.4em;font-weight:300;font-style:italic;margin:0 10px;margin-bottom:50px;text-align:center;color:#333}.testimonals-container{display:-ms-flexbox;display:flex;margin:0 auto;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center}.testimonal{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:18em;height:26em;margin:2em 1em;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between}.testimonal>p{line-height:1.4;margin:1em 0 0}.testimonal>img{display:block;width:196px;margin:0 auto;border-radius:50%}.as-seen-on{width:60em;margin:1em auto;padding:1em 0;text-align:center}.as-seen-on>img{display:block;width:100%}.as-seen-on-desc{font-size:1.5em}.break{width:60em;height:1px;border:0;background-color:#e0e0e0}.search-bar{line-height:40px;display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center}.search-input{font-size:1.2em;width:30em;max-width:80%;margin-right:10px;margin-bottom:10px;padding:.5em;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s;letter-spacing:.04em;color:inherit;border:1px solid #939393;outline:none;-webkit-box-shadow:inset 0 1px rgba(0,0,0,.1);box-shadow:inset 0 1px rgba(0,0,0,.1)}.search-input:focus{border-color:#006400;-webkit-box-shadow:0 0 2px rgba(2,184,117,.4);box-shadow:0 0 2px rgba(2,184,117,.4)}.content-center{-ms-flex:1 1 0%;flex:1 1 0%}.content-container{width:100%}.list-top{display:-ms-flexbox;display:flex;margin:0;padding:0;list-style:none;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.list-top>li{font-size:1.2em;-ms-flex:0 1 0%;flex:0 1 0%;margin:0 .5em;padding:.75em 2em;cursor:pointer;-webkit-transition:background-color .1s linear;-o-transition:background-color .1s linear;transition:background-color .1s linear}.list-top>li:first-child,.list-top>li:hover{background-color:#e0e0e0}.card-container{display:-ms-flexbox;display:flex;max-width:72em;margin:0 auto;padding:3em 0;padding-bottom:0;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center}.card{position:relative;flex-direction:column;width:20em;margin:0 1em 2em;text-align:center;border-radius:2px;background-color:#fff;-webkit-box-shadow:0 3px 5px 0 rgba(0,0,0,.14),0 0 10px 0 rgba(0,0,0,.12),0 1px 4px -1px rgba(0,0,0,.2);box-shadow:0 3px 5px 0 rgba(0,0,0,.14),0 0 10px 0 rgba(0,0,0,.12),0 1px 4px -1px rgba(0,0,0,.2)}.card,.card-content{display:-ms-flexbox;display:flex;-ms-flex-direction:column}.card-content{flex-direction:column;-ms-flex:1 1 0%;flex:1 1 0%;padding:0 2em;padding-top:3.2em;-ms-flex-pack:justify;justify-content:space-between}.project-title{font-size:1.3em;display:-ms-flexbox;display:flex;height:80px;margin-bottom:.8em;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.icon-frame{width:7em;height:7em;margin:0 auto;-webkit-transition:color .2s linear;-o-transition:color .2s linear;transition:color .2s linear;border-radius:50%;background-color:#e0e0e0}.icon-frame>i{line-height:1.7em}.project-desc{font-size:1.1em;font-weight:300;display:-ms-flexbox;display:flex;height:100px;color:#000;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.project-link{font-weight:600;text-decoration:none;color:#006400}.project-divider{width:100%;margin:0;opacity:.3;color:#e0e0e0}.project-tags{font-size:14px;font-weight:300;display:-ms-flexbox;display:flex;min-height:50px;padding:.5em 1em;text-decoration:none;color:#000;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:center;justify-content:center}.project-tags>p{margin:.2em;padding:.3em .5em;border-radius:3px;background-color:#e0e0e0;-webkit-box-shadow:3px 3px 11px -10px #000;box-shadow:3px 3px 11px -10px #000}.project-status{font-weight:500;position:absolute;top:0;right:0;padding-bottom:0;color:#006400;-ms-flex-align:end;align-items:flex-end;-ms-flex-pack:end;justify-content:flex-end}.project-status>a{float:right;padding-right:.7em;text-decoration:none;color:inherit}.project-status>a:first-child{padding-right:1.1em}.git-icon{font-size:1.2em;line-height:.8}.signup-input{font-size:1.1em;width:100%;margin:1em auto;padding:.75em;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s;letter-spacing:.04em;color:inherit;border:2px solid #e0e0e0;border-radius:4px;outline:none;-webkit-box-shadow:inset 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 2px rgba(0,0,0,.05)}.signup-input:focus{border-color:#006400;-webkit-box-shadow:0 0 2px rgba(2,184,117,.4);box-shadow:0 0 2px rgba(2,184,117,.4)}::-webkit-input-placeholder{font-weight:300;letter-spacing:normal;color:#adadad}::-moz-placeholder{font-weight:300;letter-spacing:normal;color:#adadad}@media screen and (max-width:70em){.as-seen-on,.break{width:calc(100% - 4em)}.as-seen-on{min-width:320px}}@media screen and (max-width:775px){.header-links li:nth-child(2),.header-links li:nth-child(3){display:none}.header-links{position:absolute;top:0;right:0;height:inherit}#donate-icon{display:block}}@media screen and (max-width:450px){.list-top{margin-left:4em;-ms-flex-pack:start;justify-content:flex-start}.header{padding:5px 0 0 7px}.card{width:92vw;margin:1em 0}}@media screen and (max-width:380px){.header-links li:first-child{display:none}} 2 | /*# sourceMappingURL=main.0515109c.css.map*/ -------------------------------------------------------------------------------- /docs/static/css/main.0515109c.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["index.css"],"names":[],"mappings":"AAAA,EACE,8BACQ,sBAER,kCACA,8BACI,yBAA2B,CAGjC,KACE,4BACA,gBACA,gBAEA,SACA,UAEA,aAAe,CAGjB,KACE,gBAAkB,CAIpB,QAIE,YACA,sBAEA,WACA,wBAA0B,CAO5B,sBAdE,oBACA,aAQA,sBAEI,kBAAoB,CAYzB,cALC,oBAAsB,CAOxB,kBACE,WAAa,CAGf,aACE,UAAY,CAGd,cAGE,gBACI,YAEJ,YACA,SACA,UAEA,gBAEA,WAKA,kBACI,wBAA0B,CAGhC,iCApBE,oBACA,aAYA,sBAEI,kBAAoB,CAyBzB,mBAnBC,gBACA,gBAMA,eACA,aACA,oBAEA,eACA,qBAEA,aAAe,CAQjB,eACE,iBAEA,cAAgB,CAElB,iBACE,cAAgB,CAGlB,yBACE,cACA,qBAAuB,CAGzB,aACE,YAAc,CAIhB,MACE,oBACA,aACA,uBACI,mBACJ,gBACI,YAEJ,cAAgB,CAGlB,YACE,gBAEA,iBAEA,iBAAmB,CAGrB,WACE,gBACA,gBACA,kBAEA,cACA,mBAEA,kBAEA,UAAY,CAGd,uBACE,oBACA,aAEA,cAEA,mBAEI,eACJ,qBACI,sBAAwB,CAG9B,YACE,oBACA,aACA,0BACI,sBAEJ,WACA,YACA,eAEA,qBAEI,uBACJ,sBACI,6BAA+B,CAIrC,cACE,gBAEA,cAAgB,CAGlB,gBACE,cAEA,YACA,cAEA,iBAAmB,CAGrB,YACE,WACA,gBACA,cAEA,iBAAmB,CAGrB,gBACE,cAEA,UAAY,CAGd,iBACE,eAAiB,CAGnB,OACE,WACA,WAEA,SACA,wBAA0B,CAK5B,YACE,iBAEA,oBAEA,aACA,uBACI,mBAEJ,sBAEI,mBACJ,mBACI,eACJ,qBACI,sBAAwB,CAG9B,cACE,gBAEA,WACA,cACA,kBACA,mBACA,aAEA,2BAEA,sBAEA,mBACA,qBAEA,cACA,yBACA,aACA,8CACQ,qCAA2C,CAGrD,oBACE,qBACA,8CACQ,qCAA2C,CAGrD,gBACE,gBACI,WAAa,CAGnB,mBACE,UAAY,CAMd,UACE,oBACA,aAEA,SACA,UAEA,gBAEA,sBAEI,mBACJ,qBACI,sBAAwB,CAG9B,aACE,gBAEA,gBAEI,YAEJ,cACA,kBAEA,eACA,+CACA,0CACA,sCAAyC,CAO3C,4CACE,wBAA0B,CAI5B,gBACE,oBACA,aAEA,eACA,cACA,cACA,iBAEA,mBAEI,eACJ,qBACI,sBAAwB,CAI9B,MACE,kBAMI,sBAEJ,WACA,iBAEA,kBAEA,kBACA,sBACA,wGAGQ,+FAEmC,CAG7C,oBArBE,oBAEA,aACA,yBAA2B,CAgC5B,cAVK,sBACJ,gBACI,YAEJ,cACA,kBAEA,sBAEI,6BAA+B,CAGrC,eACE,gBAEA,oBAEA,aAEA,YACA,mBAEA,sBAEI,mBACJ,qBACI,sBAAwB,CAG9B,YACE,UACA,WACA,cAEA,oCAEA,+BAEA,4BAEA,kBACA,wBAA0B,CAG5B,cACE,iBAAmB,CAGrB,cACE,gBACA,gBAEA,oBAEA,aAEA,aAEA,WAEA,sBAEI,mBACJ,qBACI,sBAAwB,CAG9B,cACE,gBAEA,qBAEA,aAAe,CAGjB,iBACE,WACA,SAEA,WACA,aAAe,CAGjB,cACE,eACA,gBAEA,oBAEA,aAEA,gBACA,iBAEA,qBAEA,WAEA,sBAEI,mBACJ,mBACI,eACJ,qBACI,sBAAwB,CAI9B,gBACE,YACA,kBAEA,kBACA,yBACA,2CACQ,kCAAqC,CAG/C,gBACE,gBAEA,kBACA,MACA,QAEA,iBAEA,cAEA,mBAEI,qBACJ,kBACI,wBAA0B,CAGhC,kBACE,YAEA,mBAEA,qBAEA,aAAe,CAGjB,8BACE,mBAAqB,CAGvB,UACE,gBACA,cAAiB,CAGnB,cACE,gBAEA,WACA,gBACA,cAEA,2BAEA,sBAEA,mBACA,qBAEA,cACA,yBACA,kBACA,aACA,iDACQ,wCAA8C,CAGxD,oBACE,qBACA,8CACQ,qCAA2C,CAGrD,4BACE,gBAEA,sBAEA,aAAe,CAGjB,mBACE,gBAEA,sBAEA,aAAe,CAIjB,mCAIE,mBAFE,sBAAwB,CAKzB,YADC,eAAiB,CAClB,CAGH,oCACE,4DAEE,YAAc,CAEhB,cACE,kBACA,MACA,QAEA,cAAgB,CAElB,aACE,aAAe,CAChB,CAGH,oCACE,UACE,gBAEA,oBAEI,0BAA4B,CAElC,QACE,mBAAqB,CAEvB,MACE,WACA,YAAc,CACf,CAGH,oCACE,6BACE,YAAc,CACf","file":"static/css/main.0515109c.css","sourcesContent":["* {\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n\n text-rendering: optimizeLegibility;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n}\n\nbody {\n font-family: 'Lato', sans-serif;\n font-size: 1.1em;\n font-weight: 300;\n\n margin: 0;\n padding: 0;\n\n color: #2a2a2a;\n}\n\n.app {\n min-height: 100vh;\n}\n\n/* Header */\n.header {\n display: -ms-flexbox;\n display: flex;\n\n height: 50px;\n padding: 0 15px 0 35px;\n\n color: #fff;\n background-color: #006400;\n\n -ms-flex-align: center;\n\n align-items: center;\n}\n\n.header-brand {\n display: -ms-flexbox;\n display: flex;\n\n text-decoration: none;\n\n -ms-flex-align: center;\n\n align-items: center;\n}\n\n.header-brand > img {\n height: 35px;\n}\n\n.header-logo {\n color: #fff;\n}\n\n.header-links {\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 4 1 0%;\n flex: 4 1 0%;\n\n height: 100%;\n margin: 0;\n padding: 0;\n\n list-style: none;\n\n color: #eee;\n\n -ms-flex-align: center;\n\n align-items: center;\n -ms-flex-pack: end;\n justify-content: flex-end;\n}\n\n.header-links > li > a {\n font-size: 1.1em;\n font-weight: 600;\n\n display: -ms-flexbox;\n\n display: flex;\n\n height: inherit;\n padding: 15px;\n padding-bottom: 12px;\n\n cursor: pointer;\n text-decoration: none;\n\n color: inherit;\n\n -ms-flex-align: center;\n\n align-items: center;\n}\n\n/* Camper Icon */\n#header-camper {\n font-size: 1.35em;\n\n height: inherit;\n}\n#header-camper > a {\n cursor: default;\n}\n\n.header-links > li > a:hover {\n color: #006400;\n background-color: #eee;\n}\n\n#donate-icon {\n display: none;\n}\n\n/* Main Section */\n.main {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: row;\n flex-direction: row;\n -ms-flex: 1 1 0%;\n flex: 1 1 0%;\n\n margin-top: 1em;\n}\n\n.main-title {\n font-size: 2.2em;\n\n margin-top: 1.5em;\n\n text-align: center;\n}\n\n.main-desc {\n font-size: 1.4em;\n font-weight: 300;\n font-style: italic;\n\n margin: 0 10px;\n margin-bottom: 50px;\n\n text-align: center;\n\n color: #333;\n}\n\n.testimonals-container {\n display: -ms-flexbox;\n display: flex;\n\n margin: 0 auto;\n\n -ms-flex-wrap: wrap;\n\n flex-wrap: wrap;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.testimonal {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n\n width: 18em;\n height: 26em;\n margin: 2em 1em;\n\n -ms-flex-align: start;\n\n align-items: flex-start;\n -ms-flex-pack: justify;\n justify-content: space-between;\n}\n\n\n.testimonal > p {\n line-height: 1.4;\n\n margin: 1em 0 0;\n}\n\n.testimonal > img {\n display: block;\n\n width: 196px;\n margin: 0 auto;\n\n border-radius: 50%;\n}\n\n.as-seen-on {\n width: 60em;\n margin: 1em auto;\n padding: 1em 0 1em;\n\n text-align: center;\n}\n\n.as-seen-on > img {\n display: block;\n\n width: 100%;\n}\n\n.as-seen-on-desc {\n font-size: 1.5em;\n}\n\n.break {\n width: 60em;\n height: 1px;\n\n border: 0;\n background-color: #e0e0e0;\n}\n\n/* Search Bar */\n\n.search-bar {\n line-height: 40px;\n\n display: -ms-flexbox;\n\n display: flex;\n -ms-flex-direction: row;\n flex-direction: row;\n\n -ms-flex-align: center;\n\n align-items: center;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.search-input {\n font-size: 1.2em;\n\n width: 30em;\n max-width: 80%;\n margin-right: 10px;\n margin-bottom: 10px;\n padding: 0.5em;\n\n -webkit-transition: all 0.2s;\n\n -o-transition: all 0.2s;\n\n transition: all 0.2s;\n letter-spacing: 0.04em;\n\n color: inherit;\n border: 1px solid #939393;\n outline: none;\n -webkit-box-shadow: inset 0 1px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px rgba(0, 0, 0, 0.1);\n}\n\n.search-input:focus {\n border-color: #006400;\n -webkit-box-shadow: 0 0 2px rgba(2, 184, 117, 0.4);\n box-shadow: 0 0 2px rgba(2, 184, 117, 0.4);\n}\n\n.content-center {\n -ms-flex: 1 1 0%;\n flex: 1 1 0%;\n}\n\n.content-container {\n width: 100%;\n}\n\n/* \n Tab Nav \n*/\n.list-top {\n display: -ms-flexbox;\n display: flex;\n\n margin: 0;\n padding: 0;\n\n list-style: none;\n\n -ms-flex-align: center;\n\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.list-top > li {\n font-size: 1.2em;\n\n -ms-flex: 0 1 0%;\n\n flex: 0 1 0%;\n\n margin: 0 0.5em;\n padding: 0.75em 2em;\n\n cursor: pointer;\n -webkit-transition: background-color 0.1s linear;\n -o-transition: background-color 0.1s linear;\n transition: background-color 0.1s linear;\n}\n\n.list-top > li:first-child {\n background-color: #e0e0e0;\n}\n\n.list-top > li:hover {\n background-color: #e0e0e0;\n}\n\n/* Card Box */\n.card-container {\n display: -ms-flexbox;\n display: flex;\n\n max-width: 72em;\n margin: 0 auto;\n padding: 3em 0;\n padding-bottom: 0;\n\n -ms-flex-wrap: wrap;\n\n flex-wrap: wrap;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n/* Card */\n.card {\n position: relative;\n\n display: -ms-flexbox;\n\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n\n width: 20em;\n margin: 0 1em 2em;\n\n text-align: center;\n\n border-radius: 2px;\n background-color: #fff;\n -webkit-box-shadow: 0 3px 5px 0 rgba(0,0,0,0.14),\n /* */ 0 0 10px 0 rgba(0,0,0,0.12),\n /* */ 0 1px 4px -1px rgba(0,0,0,0.2);\n box-shadow: 0 3px 5px 0 rgba(0,0,0,0.14),\n /* */ 0 0 10px 0 rgba(0,0,0,0.12),\n /* */ 0 1px 4px -1px rgba(0,0,0,0.2);\n}\n\n.card-content {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n -ms-flex: 1 1 0%;\n flex: 1 1 0%;\n\n padding: 0 2em;\n padding-top: 3.2em;\n\n -ms-flex-pack: justify;\n\n justify-content: space-between;\n}\n\n.project-title {\n font-size: 1.3em;\n\n display: -ms-flexbox;\n\n display: flex;\n\n height: 80px;\n margin-bottom: 0.8em;\n\n -ms-flex-align: center;\n\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.icon-frame {\n width: 7em;\n height: 7em;\n margin: 0 auto;\n\n -webkit-transition: color 0.2s linear;\n\n -o-transition: color 0.2s linear;\n\n transition: color 0.2s linear;\n\n border-radius: 50%;\n background-color: #e0e0e0;\n}\n\n.icon-frame > i {\n line-height: 1.7em;\n}\n\n.project-desc {\n font-size: 1.1em;\n font-weight: 300;\n\n display: -ms-flexbox;\n\n display: flex;\n\n height: 100px;\n\n color: black;\n\n -ms-flex-align: center;\n\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.project-link {\n font-weight: 600;\n\n text-decoration: none;\n\n color: #006400;\n}\n\n.project-divider {\n width: 100%;\n margin: 0;\n\n opacity: 0.3;\n color: #e0e0e0;\n}\n\n.project-tags {\n font-size: 14px;\n font-weight: 300;\n\n display: -ms-flexbox;\n\n display: flex;\n\n min-height: 50px;\n padding: 0.5em 1em;\n\n text-decoration: none;\n\n color: black;\n\n -ms-flex-align: center;\n\n align-items: center;\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n/* Individual Tag*/\n.project-tags > p {\n margin: 0.2em 0.2em;\n padding: 0.3em 0.5em;\n\n border-radius: 3px;\n background-color: #e0e0e0;\n -webkit-box-shadow: 3px 3px 11px -10px black;\n box-shadow: 3px 3px 11px -10px black;\n}\n\n.project-status {\n font-weight: 500;\n\n position: absolute;\n top: 0;\n right: 0;\n\n padding-bottom: 0;\n\n color: #006400;\n\n -ms-flex-align: end;\n\n align-items: flex-end;\n -ms-flex-pack: end;\n justify-content: flex-end;\n}\n\n.project-status > a {\n float: right;\n\n padding-right: 0.7em;\n\n text-decoration: none;\n\n color: inherit;\n}\n\n.project-status > a:first-child {\n padding-right: 1.1em;\n}\n\n.git-icon {\n font-size: 1.2em;\n line-height: 0.8;\n}\n\n.signup-input {\n font-size: 1.1em;\n\n width: 100%;\n margin: 1em auto;\n padding: 0.75em;\n\n -webkit-transition: all 0.2s;\n\n -o-transition: all 0.2s;\n\n transition: all 0.2s;\n letter-spacing: 0.04em;\n\n color: inherit;\n border: 2px solid #e0e0e0;\n border-radius: 4px;\n outline: none;\n -webkit-box-shadow: inset 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.signup-input:focus {\n border-color: #006400;\n -webkit-box-shadow: 0 0 2px rgba(2, 184, 117, 0.4);\n box-shadow: 0 0 2px rgba(2, 184, 117, 0.4);\n}\n\n::-webkit-input-placeholder {\n font-weight: 300;\n\n letter-spacing: normal;\n\n color: #adadad;\n}\n\n::-moz-placeholder {\n font-weight: 300;\n\n letter-spacing: normal;\n\n color: #adadad;\n}\n\n/* Media Queries */\n@media screen and (max-width: 70em) {\n .break {\n width: calc(100% - 4em);\n }\n .as-seen-on {\n width: calc(100% - 4em);\n min-width: 320px;\n }\n}\n\n@media screen and (max-width: 775px) {\n .header-links li:nth-child(2),\n .header-links li:nth-child(3) {\n display: none;\n }\n .header-links {\n position: absolute;\n top: 0;\n right: 0;\n\n height: inherit;\n }\n #donate-icon {\n display: block;\n }\n}\n\n@media screen and (max-width: 450px) {\n .list-top {\n margin-left: 4em;\n\n -ms-flex-pack: start;\n\n justify-content: flex-start;\n }\n .header {\n padding: 5px 0 0 7px;\n }\n .card {\n width: 92vw;\n margin: 1em 0;\n }\n}\n\n@media screen and (max-width: 380px) {\n .header-links li:nth-child(1) {\n display: none;\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.css"],"sourceRoot":""} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-source-for-good-directory", 3 | "version": "1.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.5.10", 7 | "react": "^15.6.1", 8 | "react-dom": "^15.6.1", 9 | "react-redux": "^5.0.5", 10 | "redux": "^3.7.1", 11 | "redux-thunk": "^2.2.0" 12 | }, 13 | "devDependencies": { 14 | "eslint-plugin-prefer-object-spread": "^1.2.1", 15 | "react-scripts": "1.0.10" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "./.setup-symlinks.sh && react-scripts build && rm -rf docs && mv build docs && rm docs/service-worker.js", 20 | "test": "react-scripts test --env=jsdom", 21 | "eject": "react-scripts eject" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/freeCodeCamp/open-source-for-good-directory.git" 26 | }, 27 | "author": "David Acosta, Francesco Agnoletto, Joe McIlhargey", 28 | "license": "BSD 3-Clause", 29 | "bugs": { 30 | "url": "https://github.com/freeCodeCamp/open-source-for-good-directory/issues" 31 | }, 32 | "homepage": "." 33 | } 34 | -------------------------------------------------------------------------------- /public/conference-for-good: -------------------------------------------------------------------------------- 1 | ../docs/conference-for-good -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeCodeCamp/open-source-for-good-directory/821b3372d06bbf1798a2896d855d2d7b9871f489/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Open Source for Good 14 | 15 | 16 | 17 | 20 |
21 | 22 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /public/league-for-good: -------------------------------------------------------------------------------- 1 | ../docs/league-for-good -------------------------------------------------------------------------------- /public/mail-for-good: -------------------------------------------------------------------------------- 1 | ../docs/mail-for-good -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "OSFG Directory", 3 | "name": "Open Source for Good Directory", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/meeting-for-good: -------------------------------------------------------------------------------- 1 | ../docs/meeting-for-good -------------------------------------------------------------------------------- /public/nonprofits.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | font-family: 'Lato', sans-serif; 7 | font-size: 1.1em; 8 | font-weight: 300; 9 | 10 | margin: 0; 11 | padding: 0; 12 | 13 | letter-spacing: 0.03em; 14 | 15 | color: #212121; 16 | background-color: #e0e0e0; 17 | } 18 | 19 | .wrapper { 20 | display: flex; 21 | flex-direction: column; 22 | 23 | border-width: 1em 0 0 0; 24 | border-style: solid; 25 | border-color: #006400; 26 | 27 | align-items: center; 28 | justify-content: center; 29 | } 30 | 31 | .fcc-banner { 32 | display: flex; 33 | 34 | padding: 2em 0; 35 | 36 | align-items: center; 37 | justify-content: center; 38 | } 39 | 40 | .fcc-banner > img { 41 | display: block; 42 | 43 | width: 30vw; 44 | min-width: 310px; 45 | } 46 | 47 | .content-container { 48 | width: 48em; 49 | margin: 0 auto 4em; 50 | 51 | border: 1px solid #adadad; 52 | border-radius: 8px; 53 | background-color: #fff; 54 | } 55 | 56 | .content-container > * { 57 | padding: 0 3em; 58 | } 59 | 60 | .repo-name { 61 | font-weight: 400; 62 | 63 | margin: 0; 64 | padding: 0.75em; 65 | 66 | text-align: center; 67 | 68 | color: #fff; 69 | border-width: 1px; 70 | border-style: solid; 71 | border-color: #006400; 72 | border-radius: 8px 8px 0 0; 73 | background-color: #006400; 74 | } 75 | 76 | .content-container h1 { 77 | margin: 0; 78 | padding: 0.5em 0; 79 | 80 | text-align: center; 81 | 82 | border-bottom: 1px solid #e0e0e0; 83 | } 84 | 85 | .content-container h2 { 86 | margin: 0; 87 | padding: 0.5em 0; 88 | 89 | text-align: center; 90 | 91 | border-bottom: 1px solid #e0e0e0; 92 | } 93 | 94 | .content-container h3 { 95 | margin: 0; 96 | padding: 1em 0; 97 | 98 | text-align: center; 99 | } 100 | 101 | .content-container ul { 102 | margin-left: 1em; 103 | } 104 | 105 | .content-container img { 106 | max-width: 100%; 107 | 108 | border-radius: 4px; 109 | } 110 | 111 | .content-container li { 112 | margin: 1em 0; 113 | } 114 | 115 | .content-container code { 116 | padding: 0.5em 1em; 117 | 118 | border-radius: 3px; 119 | background-color: #fafafa; 120 | } 121 | 122 | .project-description { 123 | font-size: 1.1em; 124 | 125 | padding-top: 30px; 126 | padding-bottom: 20px; 127 | } 128 | 129 | .project-video { 130 | max-width: 100%; 131 | margin: 40px 0; 132 | } 133 | 134 | .video-container { 135 | position: relative;overflow: hidden;height: 0; 136 | padding-bottom: 56.25%; 137 | 138 | border: 1px solid black; 139 | } 140 | 141 | .video-container iframe, 142 | .video-container object, 143 | .video-container embed { 144 | position: absolute; 145 | top: 0; 146 | left: 0; 147 | 148 | width: 100%; 149 | height: 100%; 150 | } 151 | 152 | .buttons-container { 153 | display: flex; 154 | 155 | padding: 40px 0; 156 | 157 | align-items: center; 158 | flex-wrap: wrap; 159 | justify-content: center; 160 | } 161 | 162 | button { 163 | font-size: 1.3em; 164 | font-weight: 400; 165 | line-height: 1.42857143; 166 | 167 | min-width: 190px; 168 | margin: 10px 10px; 169 | padding: 12px 20px; 170 | 171 | cursor: pointer; 172 | user-select: none; 173 | transition: background 0.2s ease-in-out, border 0.2s ease-in-out; 174 | text-align: center; 175 | vertical-align: middle; 176 | 177 | color: #292f33; 178 | border: 1px solid #f1a02a; 179 | border-radius: 4px; 180 | outline: 0; 181 | background-color: #ffac33; 182 | background-image: linear-gradient(#ffcc4d, #ffac33); 183 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 184 | } 185 | 186 | button:hover { 187 | border-color: #ec8b11; 188 | background-color: #e99110; 189 | background-image: linear-gradient(#ffcc4d, #e99110); 190 | } 191 | 192 | .body-container { 193 | padding: 40px 3em; 194 | } 195 | 196 | .contributors { 197 | display: flex; 198 | 199 | padding: 1em 3em; 200 | 201 | flex-wrap: wrap; 202 | justify-content: center; 203 | } 204 | 205 | .contributor img { 206 | position: relative; 207 | z-index: 10; 208 | 209 | width: 3.5em; 210 | height: 3.5em; 211 | margin: 3px; 212 | 213 | border-radius: 50%; 214 | } 215 | 216 | @media (max-width: 860px) { 217 | .content-container, 218 | .contributors, 219 | .contributors { 220 | width: 90vw; 221 | } 222 | } 223 | 224 | @media (max-width: 720px) { 225 | .content-container, 226 | .contributors { 227 | width: 30em; 228 | padding: 0; 229 | } 230 | .contributors { 231 | padding: 2em; 232 | } 233 | } 234 | 235 | @media (max-width: 550px) { 236 | .content-container, 237 | .contributors { 238 | width: 95vw; 239 | margin: 0; 240 | padding: 0; 241 | } 242 | .contributors { 243 | padding: 1em; 244 | } 245 | .project-description, 246 | .body-container { 247 | padding: 1em; 248 | } 249 | .project-video { 250 | min-width: 300px; 251 | margin: 25px 0; 252 | padding: 10px; 253 | } 254 | } 255 | 256 | -------------------------------------------------------------------------------- /public/open-source-for-good-directory: -------------------------------------------------------------------------------- 1 | ../docs/open-source-for-good-directory -------------------------------------------------------------------------------- /public/pantry-for-good: -------------------------------------------------------------------------------- 1 | ../docs/pantry-for-good -------------------------------------------------------------------------------- /repo-list.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "conference-for-good", 4 | "icon": "fa-users", 5 | "tags": ["conference management", "conference speakers", "speaker portal"], 6 | "status": "dev" 7 | }, 8 | { 9 | "name": "league-for-good", 10 | "icon": "fa-futbol-o", 11 | "tags": ["league management", "sports", "league"], 12 | "status": "dev" 13 | }, 14 | { 15 | "name": "mail-for-good", 16 | "icon": "fa-envelope-o", 17 | "tags": ["email", "marketing", "email campaigns"], 18 | "status": "prod" 19 | }, 20 | { 21 | "name": "meeting-for-good", 22 | "icon": "fa-globe", 23 | "tags": ["meeting", "coordination", "scheduler", "calendar", "calendar service", "google calendar"], 24 | "status": "prod" 25 | }, 26 | { 27 | "name": "pantry-for-good", 28 | "icon": "fa-cutlery", 29 | "tags": ["food-banks", "inventory", "inventory management", "charity", "donors"], 30 | "status": "prod" 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /src/actions/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import { formatRepoTitle } from '../helpers'; 3 | 4 | /* 5 | Types 6 | */ 7 | export const SET_REPO_LIST = 'SET_REPO_LIST'; 8 | export const REQUEST_REPO_DATA = 'REQUEST_REPO_DATA'; 9 | export const RECEIVE_REPO_DATA = 'RECEIVE_REPO_DATA'; 10 | export const SET_SEARCH = 'SET_SEARCH'; 11 | export const CHECK_USER = 'CHECK_USER'; 12 | export const ADD_TAG_FILTER = 'ADD_TAG_FILTER'; 13 | export const REMOVE_TAG_FILTER = 'REMOVE_TAG_FILTER'; 14 | export const SET_SORT_BY = 'SET_SORT_BY'; 15 | export const SET_USER = 'SET_USER'; 16 | 17 | /* 18 | Actions 19 | */ 20 | export function setRepoList(repos) { 21 | return { 22 | type: SET_REPO_LIST, 23 | repos 24 | }; 25 | } 26 | 27 | export function requestRepoData(repo) { 28 | return { 29 | type: REQUEST_REPO_DATA, 30 | repo: { 31 | isFetching: true, 32 | ...repo 33 | } 34 | }; 35 | } 36 | 37 | export function receiveRepoData( 38 | repo, 39 | title, 40 | description, 41 | stars, 42 | topics, 43 | issues, 44 | subscribers 45 | ) { 46 | return { 47 | type: RECEIVE_REPO_DATA, 48 | repo, 49 | title, 50 | description, 51 | stars, 52 | topics, 53 | issues, 54 | subscribers 55 | }; 56 | } 57 | 58 | export function setSearch(value) { 59 | return { 60 | type: SET_SEARCH, 61 | value 62 | }; 63 | } 64 | 65 | export function setUser(isDev) { 66 | return { 67 | type: SET_USER, 68 | isDev 69 | }; 70 | } 71 | 72 | export function addTagFilter(tag) { 73 | return { 74 | type: ADD_TAG_FILTER, 75 | tag 76 | }; 77 | } 78 | 79 | export function removeTagFilter(tag) { 80 | return { 81 | type: REMOVE_TAG_FILTER, 82 | tag 83 | }; 84 | } 85 | 86 | export function setSortBy(mode) { 87 | return { 88 | type: SET_SORT_BY, 89 | mode 90 | }; 91 | } 92 | 93 | /* 94 | Async Actions 95 | */ 96 | export function fetchGithubData(repo) { 97 | return dispatch => { 98 | dispatch(requestRepoData(repo)); 99 | const options = { 100 | headers: new Headers({ 101 | // To get Github topics 102 | Accept: 'application/vnd.github.mercy-preview+json' 103 | }) 104 | }; 105 | return fetch(`https://api.github.com/repos/freecodecamp/${repo}`, options) 106 | .then(res => res.json()) 107 | .then(data => { 108 | const title = formatRepoTitle(data.name); 109 | const description = data.description || 'Project missing description'; 110 | const stars = Number(data.stargazers_count); 111 | const topics = data.topics; 112 | const issues = Number(data.open_issues); 113 | const subscribers = Number(data.subscribers_count); 114 | dispatch( 115 | receiveRepoData( 116 | repo, 117 | title, 118 | description, 119 | stars, 120 | topics, 121 | issues, 122 | subscribers 123 | ) 124 | ); 125 | }) 126 | .catch(err => console.log(err)); 127 | }; 128 | } 129 | -------------------------------------------------------------------------------- /src/assets/fcc-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeCodeCamp/open-source-for-good-directory/821b3372d06bbf1798a2896d855d2d7b9871f489/src/assets/fcc-logo-white.png -------------------------------------------------------------------------------- /src/components/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { addTagFilter, removeTagFilter } from '../actions'; 5 | 6 | const Card = ({ 7 | processTag, 8 | description, 9 | tagFilters, 10 | icon, 11 | isDev, 12 | issues, 13 | link, 14 | name, 15 | stars, 16 | subscribers, 17 | tags, 18 | title 19 | }) => { 20 | const tagsArray = tags.map(tag => { 21 | const included = tagFilters.includes(tag); 22 | return ( 23 |

processTag(e)} 26 | style={{ 27 | cursor: 'pointer', 28 | backgroundColor: included ? '#FF6D58' : null, 29 | color: included ? 'white' : null, 30 | fontWeight: included ? 700 : '', 31 | userSelect: 'none' 32 | }} 33 | > 34 | {tag} 35 |

36 | ); 37 | }); 38 | return ( 39 |
40 |
41 | 45 |

46 |