├── .prettierrc ├── MIT_LICENSE ├── README.md ├── images ├── dino.svg ├── flag-orpheus-top.png ├── github.svg ├── pr.svg └── slack.svg ├── index.html ├── script.js └── style.css /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "tabWidth": 2, 4 | "printWidth": 80, 5 | "semi": true, 6 | "singleQuote": false 7 | } 8 | -------------------------------------------------------------------------------- /MIT_LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2022 Hack Club 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Contribute to Hack Club 2 | 3 | Hack Club is a nonprofit network of high school coding clubs and makers around the world. The Hack Club community has over 250 open source repositories, many of which are being actively developed every day. What makes these repositories open source is that they are editable by the public, which encourages you, the Hack Club community, to come together and work on code socially. Contributions can be made in many ways, like tracking bugs and features by opening a GitHub issue, editing code by creating a GitHub pull request, and reviewing pull requests made by others. We welcome and encourage your contributions, and we look forward to seeing the things you create! 4 | 5 | ## How it works 6 | 7 | This page uses GitHub's unauthenticated API to pull down public repositories from an organization. We use JavaScript to clone an example element and use that to populate the repository elements on the page. 8 | 9 | ## Contributing 10 | 11 | Contributions are encouraged and welcome! Feel free to submit a pull request with code changes, or open issues for suggestions or bug reports. 12 | 13 | Development chatter happens in the [#hackclub-site-dev](https://app.slack.com/client/T0266FRGM/C036BTDGP43) channel in the [Hack Club Slack](https://hackclub.com/slack/). 14 | 15 | ## Running Locally 16 | 17 | 1. Clone this repository 18 | - `git clone https://github.com/hackclub/contribute.git && cd contribute` 19 | 1. Start server 20 | - `python -m SimpleHTTPServer` 21 | 1. View your server 22 | - `open http://localhost:8000/` 23 | 24 | ## Debugging Tools 25 | 26 | There are some special URL fragments you can add to test things: 27 | 28 | * `#force-no-repos` will force the "no repositories with open issues" message to show 29 | * `#force-loader` will force the loader to show infinitely 30 | * `#force-error` will force the error message to show -------------------------------------------------------------------------------- /images/dino.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /images/flag-orpheus-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/contribute/63240f962648cdcc120b288fd186c125f9056518/images/flag-orpheus-top.png -------------------------------------------------------------------------------- /images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /images/pr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /images/slack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Contribute to Hack Club 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 31 | 37 | 41 | 42 | 47 | 48 | 49 | 50 | 56 | 57 |
58 |

Contribute to Hack Club

59 |

60 | A list of active 61 | Hack Club 62 | open source repositories on 63 | GitHub 64 |

65 |
66 | 67 |
68 |

69 | Hack Club is a 70 | nonprofit network of high school coding clubs and makers around the 72 | world. The Hack Club community has 74 | over 250 open source repositories, many 75 | of which are being actively developed every day. What makes these 76 | repositories open source is that they are 77 | editable by the public, which encourages 78 | you, the Hack Club community, to come together and collaborate on code 79 | socially. 80 |

81 | 82 |

83 | Transparency is a core value of Hack Club, and code is not the only 84 | thing we open source. 85 | 86 | Check out our finances, workshops, and more. 87 | 88 |

89 | 90 |

91 | We 92 | welcome and encourage your contributions, 93 | and we look forward to seeing the things you create! 94 |

95 | 96 |

97 | 98 | Looking to contribute but don't know how? 99 | We have you covered! 101 |

102 |
103 | 104 |
105 |
106 |

Active Repositories

107 | 111 | 112 |
113 | 114 |
115 | Fetching the latest list of repositories. Hang tight... 116 |
117 |
118 | 119 | 131 | 132 | 159 |
160 |
161 | 162 |
163 |
164 |

How do I contribute?

165 |

166 | If you're new here, scroll down for steps to 167 | get started! 168 |

169 |

170 | 171 | Note: This guide assumes you have a 172 | GitHub account, 173 | git 178 | set up on your machine, and a 179 | text editor 182 | for editing the code. 183 | 184 |

185 | 186 |
    187 |
  1. 188 | 192 | Review our contribution guidelines 193 | 194 |

    195 | This document contains a set of guidelines which any contributions 196 | to any Hack Club repository must follow. 197 |

    198 |
  2. 199 |
  3. 200 | 201 | Find a repository to contribute to 202 | 203 |

    204 | Contributions can happen in a lot of ways. Adding 205 | issues, creating pull requests, 206 | and reviewing 207 | existing pull requests are a few of those ways. 208 |

    209 |
  4. 210 |
  5. 211 | 215 | Fork the repository 216 | 217 |

    218 | A fork is a copy of a repository that you manage. Forks let you 219 | make changes to a project without affecting the original code. You 220 | can create this copy by clicking on the "Fork" button at the top 221 | right of the repository page. 222 |

    223 |
  6. 224 | 225 |
  7. 226 | 230 | Clone the repository and open it in your code 231 | editor 232 | 233 |

    234 | Cloning a repository is how you download the repository's code to 235 | your computer. You can clone the repository by clicking the green 236 | "Code" button on the repository page. 237 |

    238 |
  8. 239 | 240 |
  9. 241 | 245 | When you're done making your code edits, create a 246 | pull request 247 | 248 |

    249 | Pull requests are how you suggest your code edits! The maintainers 250 | of the repository may comment on your pull request, ask for 251 | changes, or approve it right away and merge it in. 252 |

    253 |
  10. 254 |
255 |

256 | 257 | Congratulations, you're now an 258 | open source contributor! 259 | 260 |

261 |
262 |
263 |
264 |

New here? Welcome!

265 |

266 | Hack Club 267 | is a nonprofit network of high school coding clubs and makers around 268 | the world. We are so happy to have you! 269 |

270 |
    271 |
  1. 272 | 273 | 1. Join our online community 274 | 275 |

    276 | We’ve got a 24/7 Slack chatroom of 25k+ teenagers learning to 277 | code & building amazing projects, & you’ll fit right in. 278 |

    279 | Slack logo 280 |
  2. 281 | 282 |
  3. 283 | 284 | 2. Join GitHub 285 | 286 |

    287 | GitHub is a development platform where people collaborate on 288 | code. This is where we can find and edit each others code. 289 |

    290 | GitHub logo 291 |
  4. 292 | 293 |
  5. 294 | 295 | 3. Make your first pull request 296 | 297 |

    298 | Pull requests are the way we edit each others code. Follow the 299 | link above for an interactive demonstation on how to make a pull 300 | request! 301 |

    302 | Dino PR 303 |
  6. 304 | 305 |
  7. 306 | 307 | 4. Share your work on Scrapbook 308 | 309 |

    310 | As a Hack Clubber, you are always learning and building things. 311 | Scrapbook allows you to share updates on the things you're doing 312 | with the rest of the Hack Club community. 313 |

    314 | Scrap 315 |
  8. 316 | 317 |
  9. 318 | 319 | 5. Contribute to more open source projects 320 | 321 |

    322 | Once you feel ready, you can start to contribute to other open 323 | source projects! 324 |

    325 | Dinosaur waving 330 |
  10. 331 |
332 |
333 |
334 |
335 | 336 | 337 | 338 | 339 | 340 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("DOMContentLoaded", (event) => { 2 | showLoader(); 3 | 4 | let hash = window.location.hash; 5 | 6 | if (hash == "#force-no-repos") { 7 | // Force the "no repos" message to show 8 | showEmptyMessage(); 9 | } else if (hash == "#force-loader") { 10 | Function.prototype(); // A no-op to keep the loader showing forever 11 | } else if (hash == "#force-error") { 12 | hideLoader(); 13 | showErrorMessage(); 14 | } else { 15 | loadAndRenderRepos(); 16 | } 17 | 18 | 19 | function loadAndRenderRepos() { 20 | let url = "https://hackclub.com/api/contribute/"; 21 | 22 | fetch(url) 23 | .then(function (response) { 24 | if (response.ok) { 25 | return response.json(); 26 | } else { 27 | return { then: function () { } }; // end the promise chain 28 | } 29 | }) 30 | .then(function (resp) { 31 | hideLoader(); 32 | let repos = resp.repositories.nodes; 33 | 34 | if (repos.length > 0) { 35 | const maxReposToShow = 20; 36 | let shownRepoCount = 0; 37 | for (let i = 0; (shownRepoCount < maxReposToShow) && i < repos.length; i++) { 38 | // Open issue count 39 | let openIssuesCount = repos[i].issues.totalCount; 40 | if (openIssuesCount > 0) { 41 | shownRepoCount++; 42 | let reposListEl = document.querySelector("[data-tag='repos'] ul"); 43 | let exampleEl = document.querySelector("[data-tag='example-repo']"); 44 | 45 | let repoEl = exampleEl.cloneNode(true); 46 | repoEl.classList.remove("hidden"); 47 | 48 | repoEl.querySelector("[data-tag='repo-link']").href = 49 | repos[i].url; 50 | 51 | // Format open issues language 52 | let formattedText = openIssuesCount == 1 ? " issue" : " issues"; 53 | 54 | repoEl.querySelector("[data-tag='issues-count']").innerText = 55 | openIssuesCount + formattedText; 56 | 57 | // Name 58 | repoEl.querySelector("[data-tag='name']").innerText = repos[i].name; 59 | 60 | // Description 61 | repoEl.querySelector("[data-tag='description']").innerText = 62 | repos[i].description; 63 | 64 | // Language 65 | // Can occasionally be null 66 | languageEl = repoEl.querySelector("[data-tag='language']"); 67 | if (repos[i].languages.nodes.length > 0) { 68 | languageEl.innerText = repos[i].languages.nodes[0].name; 69 | } else { 70 | languageEl.classList.add("hidden"); 71 | } 72 | 73 | // Pushed at date 74 | let currentDate = new Date(); 75 | let pushedAtDate = new Date(repos[i].pushedAt); 76 | 77 | let diffInMS = currentDate.getTime() - pushedAtDate.getTime(); 78 | let diffInDays = Math.floor(diffInMS / (1000 * 3600 * 24)); 79 | 80 | let dateText; 81 | 82 | if (diffInDays == 0) { // less than 24 hours ago, so we'll be more precise 83 | if (diffInMS < 1000 * 60 * 60) { // 1 hour 84 | let diffInMin = Math.floor(diffInMS / (1000 * 60)); 85 | if (diffInMin <= 5) { 86 | dateText = "just now!"; 87 | } else { 88 | dateText = diffInMin + " minutes ago"; 89 | } 90 | } else { 91 | let diffInHr = Math.floor(diffInMS / (1000 * 60 * 60)); 92 | dateText = diffInHr + " hour" + (diffInHr == 1 ? "" : "s") + " ago"; 93 | } 94 | } else { 95 | dateText = diffInDays + " day" + (diffInDays == 1 ? "" : "s") + " ago"; 96 | } 97 | 98 | repoEl.querySelector("[data-tag='last-push']").innerText = 99 | "Last updated " + dateText; 100 | 101 | reposListEl.appendChild(repoEl); 102 | } 103 | } 104 | } else { 105 | showEmptyMessage(); 106 | } 107 | }) 108 | .catch(function (err) { 109 | console.log("Fetching " + url + " failed"); 110 | console.log("Error: " + err); 111 | showErrorMessage(); 112 | }); 113 | } 114 | 115 | function showEmptyMessage() { 116 | let noReposEl = document.querySelector("[data-tag='no-repos']"); 117 | noReposEl.classList.remove("hidden"); 118 | } 119 | 120 | function hideLoader() { 121 | let loaderEl = document.querySelector("[data-tag='loader']"); 122 | loaderEl.classList.add("hidden"); 123 | } 124 | 125 | function randomLoadMessage() { 126 | const loadMessages = [ 127 | "Loading the list of repos...", 128 | "Reticulating repositories...", 129 | "Fetching the freshest repos...", 130 | "Getting the down-low on these downloads...", 131 | "Getting the low-down on these downloads...", 132 | "It's a contribution conspiracy!", 133 | "It's a contribution conglomerate!", 134 | "It's a contribution conga-line!", 135 | "It's a conga line of contributions!", 136 | "Contribution and retribution...", 137 | "Putting the 'repo' in 'repository'...", 138 | "Putting the 'con' in 'contribution'...", 139 | "Putting the 'rib' in 'contribution'...", 140 | "Putting the 'open' in 'open source software'...", 141 | "Putting the 'sour' in 'open source software'...", 142 | "Putting the 'soft' in 'open source software'...", 143 | "Putting the 'pen' in 'open source software'...", 144 | "Created by viewers like you...", 145 | "Repostravaganza!", 146 | "That's a lot of repos...", 147 | "Side-loading repos...", 148 | "Downloading repos, uploading repos, all-around-loading repos...", 149 | "Now for my next trick...", 150 | "Now for my next trick, I'll pull a repo from my hat!", 151 | "Was... THIS your card?", 152 | "Was... THIS your repo?", 153 | "Was... THIS your contribution?", 154 | "Pulling from the repo of life...", 155 | "Pulling from the repo of repos...", 156 | "Pulling from the repo of contributions...", 157 | "Loading code from the repos...", 158 | "Loading repos from the code...", 159 | "Repos loading from the code...", 160 | "Code loading from the repos...", 161 | "Code repo from the loading...", 162 | "Repos coding from the loading...", 163 | "Commit, push, repeat...", 164 | "Commit, rinse, repeat... wait?", 165 | "Communicating with the contribution code...", 166 | "Reuniting with the repos...", 167 | "Communing with the contributions...", 168 | "git commit -m 'Fix repo loading message'...", 169 | "git commit -m 'Faster repo list load times'...", 170 | "git commit -m 'More loading'...", 171 | "echo 'patience is a virtue...' | cowsay | lolcat", 172 | "Importing repo (1/185,627,198)...", 173 | "While you wait for this to load... twitter.com/thestrangelog", 174 | ]; 175 | return loadMessages[Math.floor(Math.random() * loadMessages.length)]; 176 | } 177 | 178 | function showLoader() { 179 | let loaderEl = document.querySelector(".loading-text"); 180 | loaderEl.innerHTML = randomLoadMessage(); 181 | } 182 | 183 | function showErrorMessage() { 184 | let errorEl = document.querySelector("[data-tag='error']"); 185 | errorEl.classList.remove("hidden"); 186 | } 187 | }); 188 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Baloo+2:wght@800&family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Smythe&display=swap"); 2 | 3 | header { 4 | background: var(--cyan); 5 | background-image: url(images/pr.svg); 6 | background-repeat: repeat; 7 | color: var(--white); 8 | padding: var(--spacing-6) var(--spacing-0) var(--spacing-6); 9 | text-align: center; 10 | } 11 | 12 | ul { 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | ul { 18 | list-style-type: none; 19 | } 20 | 21 | .banner { 22 | position: absolute; 23 | top: -10px; 24 | left: var(--spacing-4); 25 | } 26 | 27 | .banner img { 28 | height: 80px; 29 | } 30 | 31 | .banner:hover img { 32 | animation: wave-flag 0.5s linear infinite alternate; 33 | } 34 | 35 | @media (prefers-reduced-motion: reduce) { 36 | .banner:hover img { 37 | transition: 0.1875s cubic-bezier(0.375, 0, 0.675, 1) transform; 38 | transform-origin: top left; 39 | } 40 | } 41 | 42 | @keyframes wave-flag { 43 | 0% { 44 | transform: rotate(0deg); 45 | } 46 | 100% { 47 | transform: rotate(-5deg); 48 | } 49 | } 50 | 51 | .card { 52 | font-size: var(--font-3); 53 | } 54 | 55 | .blurb { 56 | border-radius: var(--radii-default); 57 | padding: var(--spacing-4); 58 | } 59 | 60 | .blurb p { 61 | line-height: 1.75; 62 | } 63 | 64 | header > p, 65 | header > p > a { 66 | color: var(--white) !important; 67 | } 68 | 69 | .container { 70 | margin: var(--spacing-5) auto; 71 | } 72 | 73 | .no-repos { 74 | color: var(--white); 75 | font-style: italic; 76 | } 77 | 78 | .repos { 79 | background: radial-gradient(#e66465, #9198e5); 80 | padding: var(--spacing-4) 0; 81 | } 82 | 83 | .repos h2 { 84 | margin-bottom: var(--spacing-4); 85 | } 86 | 87 | .repos ul { 88 | display: grid; 89 | grid-template-columns: 1fr 1fr; 90 | gap: var(--spacing-3); 91 | } 92 | 93 | @media (max-width: 768px) { 94 | .repos ul { 95 | grid-template-columns: 1fr; 96 | } 97 | } 98 | 99 | .repo { 100 | margin: 0; 101 | } 102 | 103 | .repo .description { 104 | min-height: 50px; 105 | } 106 | 107 | .issues-count, 108 | .language { 109 | float: right; 110 | margin-right: var(--spacing-1); 111 | top: 0; 112 | } 113 | 114 | /* How to contribute section */ 115 | #how-do-i-contribute { 116 | font-size: var(--font-4); 117 | } 118 | 119 | /* Shared styles */ 120 | .hidden { 121 | display: none; 122 | } 123 | 124 | .highlight { 125 | background-image: linear-gradient( 126 | -100deg, 127 | rgba(243, 234, 164, 0.33), 128 | rgba(243, 234, 164, 0.95), 129 | rgba(243, 234, 164, 0.1) 130 | ); 131 | } 132 | 133 | .no-styles-a { 134 | color: inherit; 135 | text-decoration: none; 136 | text-underline-position: under; 137 | } 138 | 139 | .no-styles-a:hover { 140 | color: var(--primary); 141 | text-decoration: none; 142 | text-underline-position: under; 143 | } 144 | 145 | #active-repositories { 146 | color: var(--white); 147 | } 148 | 149 | .new ol { 150 | display: grid; 151 | grid-template-columns: 1fr 1fr 1fr; 152 | gap: var(--spacing-3); 153 | padding-inline-start: 0 !important; /* overide default padding-inline-start */ 154 | } 155 | 156 | .new li { 157 | position: relative; 158 | } 159 | 160 | .new li:nth-child(odd) { 161 | background-color: var(--cyan); 162 | } 163 | 164 | .new li:nth-child(even) { 165 | background-color: var(--cyan); 166 | } 167 | 168 | @media screen and (max-width: 768px) { 169 | .involveBig ol { 170 | grid-template-columns: 1fr 1fr; 171 | } 172 | } 173 | 174 | @media screen and (max-width: 520px) { 175 | .involveBig ol { 176 | grid-template-columns: 1fr; 177 | } 178 | } 179 | 180 | .card-design { 181 | position: absolute; 182 | bottom: -30px; 183 | right: -5px; 184 | font-family: "Baloo 2", cursive; 185 | opacity: 20%; 186 | font-size: 60px; 187 | } 188 | 189 | .involve { 190 | color: var(--white); 191 | } 192 | .involve h3 { 193 | font-size: var(--font-5); 194 | } 195 | 196 | .involve p { 197 | font-size: var(--font-3); 198 | color: var(--white); 199 | } 200 | 201 | .involve a { 202 | font-size: var(--font-4); 203 | color: var(--white); 204 | } 205 | 206 | .involve img { 207 | height: 40%; 208 | position: absolute; 209 | bottom: -5%; 210 | right: -5%; 211 | opacity: 20%; 212 | } 213 | 214 | .dino-svg { 215 | opacity: 50% !important; 216 | } 217 | 218 | .loader { 219 | width: 48px; 220 | height: 48px; 221 | border: 5px solid var(--slate); 222 | border-bottom-color: var(--red); 223 | border-radius: 50%; 224 | display: inline-block; 225 | box-sizing: border-box; 226 | animation: rotation 1s linear infinite; 227 | align-self: center; 228 | margin: var(--spacing-3); 229 | } 230 | 231 | @keyframes rotation { 232 | 0% { 233 | transform: rotate(0deg); 234 | } 235 | 100% { 236 | transform: rotate(360deg); 237 | } 238 | } 239 | 240 | .loading-text { 241 | color: var(--muted); 242 | text-align: center; 243 | } 244 | 245 | .loader-container:not(.hidden) { 246 | display: flex; 247 | justify-content: center; 248 | flex-direction: column; 249 | } 250 | 251 | .error-container:not(.hidden) { 252 | display: flex; 253 | justify-content: center; 254 | flex-direction: column; 255 | } 256 | 257 | .error-icon { 258 | margin: var(--spacing-3); 259 | height: var(--font-7); 260 | } --------------------------------------------------------------------------------