├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── README.md ├── build-make.js ├── build-sync.js ├── build.js ├── config.js ├── elements ├── contributor-list.css ├── contributor-list.js ├── readme-panel.css ├── readme-panel.js ├── repo-list-item.css ├── repo-list-item.js ├── repo-list.css └── repo-list.js ├── highlight.js ├── index.css ├── index.js ├── intro.md ├── package-lock.json ├── package.json └── static ├── font ├── FantasqueSansMono-Bold.eot ├── FantasqueSansMono-Bold.svg ├── FantasqueSansMono-Bold.woff ├── FantasqueSansMono-BoldItalic.eot ├── FantasqueSansMono-BoldItalic.svg ├── FantasqueSansMono-BoldItalic.woff ├── FantasqueSansMono-RegItalic.eot ├── FantasqueSansMono-RegItalic.svg ├── FantasqueSansMono-RegItalic.woff ├── FantasqueSansMono-Regular.eot ├── FantasqueSansMono-Regular.svg ├── FantasqueSansMono-Regular.woff ├── fantasque.css ├── index.css ├── stackgl.css ├── stackgl.eot ├── stackgl.svg ├── stackgl.ttf └── stackgl.woff └── index.html /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Deploy 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | gollum # gollum is the github wiki 9 | 10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 11 | jobs: 12 | deploy: 13 | # The type of runner that the job will run on 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | node-version: [8.11.4] 18 | # Steps represent a sequence of tasks that will be executed as part of the job 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v1 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | 26 | - name: Cache db 27 | id: cache-db 28 | uses: actions/cache@v1 29 | with: 30 | path: .data 31 | nkey: ${{ runner.os }}-dbcache 32 | 33 | # Runs a single command using the runners shell 34 | - name: Install and build 35 | run: npm install 36 | env: 37 | ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | DEBUG: "*" 39 | 40 | - name: Deploy 🚀 41 | uses: JamesIves/github-pages-deploy-action@releases/v3 42 | with: 43 | ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | BRANCH: gh-pages # The branch the action should deploy to. 45 | FOLDER: dist # The folder the action should deploy. 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .data 3 | dist 4 | npm-debug.log 5 | packages.md 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [stack.gl/packages](http://stack.gl/packages/) 2 | 3 | This is where we keep all of our packages' documentation for safe keeping and discoverability, both inside the [stackgl organisation](https://github.com/stackgl) and out. 4 | 5 | This branch is responsible for downloading data from the GitHub API using [ecosystem-docs](https://github.com/hughsk/ecosystem-docs), transforming it into a nice format and presenting it on the frontend. 6 | 7 | The built output can be found on the [gh-pages branch](https://github.com/stackgl/packages/tree/gh-pages) of this repository. 8 | 9 | ## Adding a package 10 | 11 | Simply add your package's GitHub repository to [the list in the wiki](https://github.com/stackgl/packages/wiki/Packages). 12 | 13 | ## Build your own list 14 | 15 | This repository has been designed to be easily forkable for other ecosystems to take advantage of, with the hopes of more flexibility becoming available in the future. 16 | 17 | First off: if you're just interested in the syncing behaviour you should check out [ecosystem-docs](https://github.com/hughsk/ecosystem-docs). 18 | 19 | Otherwise: 20 | 21 | 1. Fork the repository and clone it to your machine. 22 | 1. Update `config.js` to alter variables specific to your project, such as the logo content or packages list URL. (There's a bit of JSX in there right now. Sorry!) 23 | 1. Update `intro.md` to change the content of the intro page. 24 | 1. Install the dependencies using `npm install`. This will likely prompt you for your GitHub username and password. 25 | 1. Start the app by running `npm start` and visiting `http://localhost:3000/` when ready. 26 | 1. Whenever you want to update the list, run `npm run sync`. 27 | 1. Once you're ready to deploy, run `npm run deploy` to build the site and and push it to GitHub pages. 28 | 1. Enjoy! :sparkles: 29 | -------------------------------------------------------------------------------- /build-make.js: -------------------------------------------------------------------------------- 1 | require('node-jsx').install() 2 | 3 | const make = require('./build').make 4 | const highlight = require('./highlight') 5 | const marked = require('marked') 6 | const path = require('path') 7 | const fs = require('fs') 8 | 9 | const intro = fs.readFileSync(path.join(__dirname, 'intro.md'), 'utf8') 10 | const file = fs.readFileSync(path.join(__dirname, 'packages.md'), 'utf8') 11 | 12 | make(file, {}, function(err) { 13 | if (err) throw err 14 | 15 | marked(intro, { 16 | highlight: highlight 17 | }, function(err, html) { 18 | if (err) throw err 19 | 20 | fs.writeFileSync(path.join(__dirname, 'dist', 'intro.html'), html) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /build-sync.js: -------------------------------------------------------------------------------- 1 | require('node-jsx').install() 2 | 3 | const sync = require('./build').sync 4 | const config = require('./config') 5 | const request = require('request') 6 | const path = require('path') 7 | const fs = require('fs') 8 | 9 | request.get(config.wiki, function(err, res, body) { 10 | if (err) throw err 11 | 12 | fs.writeFileSync(path.join(__dirname, 'packages.md'), body) 13 | 14 | sync(body, function(err, repos) { 15 | if (err) { 16 | console.error('*********sync failed*********'); 17 | throw err; 18 | } 19 | console.log(repos.length + ' repos updated') 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | const read = require('ecosystem-docs/read') 2 | const sync = require('ecosystem-docs/sync') 3 | const highlight = require('./highlight') 4 | const map = require('map-limit') 5 | const cheerio = require('cheerio') 6 | const marked = require('marked') 7 | const mkdirp = require('mkdirp') 8 | const ghauth = require('ghauth') 9 | const mdast = require('mdast') 10 | const path = require('path') 11 | const cpr = require('cpr') 12 | const fs = require('fs') 13 | 14 | const dataLocation = path.join(__dirname, '.data') 15 | 16 | exports.sync = function(packageMarkdown, done) { 17 | const repos = categoriesToRepos(parseCategories(packageMarkdown)) 18 | 19 | function syncWithToken(token){ 20 | sync(repos, { 21 | data: dataLocation, 22 | token, token 23 | }, done); 24 | } 25 | 26 | if(process.env.ACCESS_TOKEN){ 27 | syncWithToken(process.env.ACCESS_TOKEN); 28 | }else{ 29 | console.log("No access token passed need to authenticate..."); 30 | ghauth({ 31 | configName: 'ecosystem-docs', 32 | userAgent: 'ecosystem-docs', 33 | scopes: ['user'] 34 | }, function(err, auth) { 35 | if (err) return done(err) 36 | syncWithToken(auth.token) 37 | }) 38 | } 39 | } 40 | 41 | exports.make = function(packageMarkdown, options, done) { 42 | options = options || {} 43 | 44 | const categories = parseCategories(packageMarkdown) 45 | const repoList = categoriesToRepos(categories) 46 | 47 | options.output = options.output || path.join(__dirname, 'dist') 48 | 49 | read(repoList, { 50 | data: dataLocation 51 | }, function(err, repos) { 52 | if (err) return done(err) 53 | 54 | const contribs = indexContributors(repos) 55 | 56 | reattachCategories(repos, categories) 57 | map(repos, 20, function(repo, next) { 58 | writeRepoJSON(repo, options, function(err) { 59 | if (err) return next(err) 60 | 61 | next(null, { 62 | user: repo.user, 63 | name: repo.name, 64 | stars: repo.stars, 65 | issues: repo.issues, 66 | contrib: repo.contributors, 67 | version: repo.package && repo.package.version || false, 68 | npmName: repo.package && repo.package.name || false, 69 | category: repo.category 70 | }) 71 | }) 72 | }, function(err, repos) { 73 | if (err) return done(err) 74 | 75 | const index = { 76 | repos: reposToCategories(repos), 77 | contributors: contribs 78 | } 79 | 80 | fs.writeFile( 81 | path.join(options.output, 'index.json'), 82 | JSON.stringify(index), 83 | copyAssets 84 | ) 85 | }) 86 | }) 87 | 88 | function copyAssets(err) { 89 | if (err) return done(err) 90 | 91 | cpr(path.join(__dirname, 'static'), options.output, function(err) { 92 | return done(err) 93 | }) 94 | } 95 | } 96 | 97 | function writeRepoJSON(repo, options, done) { 98 | const dest = path.join(options.output, repo.user, repo.name) + '.json' 99 | const data = {} 100 | 101 | mkdirp(path.dirname(dest), function(err) { 102 | if (err) return done(err) 103 | 104 | convertReadme(repo, function(err, readme) { 105 | if (err) return done(err) 106 | data.readme = readme 107 | fs.writeFile(dest, JSON.stringify(data), done) 108 | }) 109 | }) 110 | } 111 | 112 | function convertReadme(repo, done) { 113 | const ast = mdast.parse(repo.readme) 114 | 115 | // Remove all content before the first heading 116 | for (var i = 0; i < ast.children.length; i++) { 117 | var child = ast.children[i] 118 | if (child.type === 'heading') break 119 | ast.children.splice(i--, 1) 120 | } 121 | 122 | // Ensure there's only one

in the document, 123 | // and that

's that are code-only are at least

124 | for (; i < ast.children.length; i++) { 125 | var child = ast.children[i] 126 | if (child.type !== 'heading') continue 127 | if (child.depth === 1) child.depth = 2 128 | if (child.depth === 2) { 129 | if (child.children.length !== 1) continue 130 | if (child.children[0].type !== 'inlineCode') continue 131 | child.depth = 3 132 | } 133 | } 134 | 135 | marked(mdast.stringify(ast), { 136 | highlight: highlight 137 | }, function(err, html) { 138 | if (err) return done(err) 139 | 140 | var $ = cheerio.load(html) 141 | 142 | // Remove badges 143 | $('img[src*="://img.shields.io"]').remove() 144 | $('img[src*="://badges.github.io"]').remove() 145 | $('img[src*="://nodei.co"]').remove() 146 | $('img[src*="://david-dm.org"]').remove() 147 | $('img[src*="://badge.fury.io"]').remove() 148 | $('img[src*="://travis-ci.org"]').remove() 149 | $('img[src*="://secure.travis-ci.org"]').remove() 150 | 151 | $('h1 img').remove() 152 | 153 | // Resolve relative URLs in READMEs for images and anchors 154 | $('a:not([href^=http]):not([href^=#])').each(function(i,el) { 155 | var $a = $(el) 156 | $a.attr('href', 'http://github.com/' + repo.user + '/' + repo.name + '/blob/master/' + $a.attr('href')) 157 | }) 158 | 159 | $('img:not([src^=http])').each(function(i,el) { 160 | var $img = $(el) 161 | $img.attr('src', 'https://raw.githubusercontent.com/' + repo.user + '/' + repo.name + '/master/' + $img.attr('src')) 162 | }) 163 | 164 | // Guarantee that the first heading is an

, 165 | // and wrap it up in an link to the repository. 166 | var headings = $('h1, h2, h3, h4, h5, h6') 167 | if (headings && headings[0] && repo.path) { 168 | $(headings[0]).replaceWith($( 169 | '

' 170 | + '' 171 | + $(headings[0]).text() 172 | + '' 173 | + '
' 174 | + '

' 175 | )) 176 | } 177 | 178 | if (!repo.page) return done(null, $.html()) 179 | 180 | var $iframe = $('') 181 | var $img = $('img') 182 | var replaced = false 183 | var headCount = 0 184 | 185 | // Try and replace the first image in the first section 186 | // with a gh-pages iframe if present. 187 | $('h1, h2, h3, h4, h5, h6, img').each(function(i, el) { 188 | if (headCount++ !== 1 || el.name !== 'img') return 189 | var $el = $(el) 190 | if ($el.parent()[0].name === 'a') $el = $el.parent() 191 | $el.replaceWith($iframe) 192 | replaced = true 193 | }) 194 | 195 | if (!replaced) { 196 | if (headings[1]) { 197 | // Insert before the second heading 198 | $(headings[1]).before($iframe) 199 | } else { 200 | // Or insert after the first, if there's only one 201 | $(headings[0]).after($iframe) 202 | } 203 | } 204 | 205 | done(null, $.html()) 206 | }) 207 | } 208 | 209 | function indexContributors(repos) { 210 | const contribs = [] 211 | const avatars = [] 212 | 213 | repos.forEach(function(repo) { 214 | repo.contributors = repo.contributors.map(function(user) { 215 | var name = user.login 216 | var idx = contribs.indexOf(name) 217 | if (idx !== -1) return idx 218 | contribs.push(name) 219 | avatars.push(user.avatar_url) 220 | return contribs.length - 1 221 | }) 222 | }) 223 | 224 | return contribs.map(function(d, i) { 225 | return { name: d, image: avatars[i] } 226 | }) 227 | } 228 | 229 | function parseCategories(packageMarkdown) { 230 | const tree = mdast.parse(String(packageMarkdown)) 231 | const repos = {} 232 | 233 | var category = null 234 | 235 | tree.children.forEach(function(node) { 236 | const type = node.type 237 | 238 | if (type === 'heading') { 239 | return category = mdast 240 | .stringify(node) 241 | .replace(/^\#+/g, '') 242 | .trim() 243 | } else 244 | if (type !== 'list' || category === null) { 245 | return 246 | } 247 | 248 | repos[category] = node.children.map(function(child) { 249 | return mdast.stringify(child) 250 | }) 251 | }) 252 | 253 | return repos 254 | } 255 | 256 | function categoriesToRepos(categories) { 257 | return Object.keys(categories).reduce(function(memo, key) { 258 | const repos = categories[key] 259 | 260 | repos.forEach(function(repo) { 261 | repo.category = key 262 | }) 263 | 264 | return memo.concat(repos) 265 | }, []) 266 | } 267 | 268 | function reposToCategories(repos) { 269 | return repos.reduce(function(categories, repo) { 270 | var key = repo.category 271 | delete repo.category 272 | categories[key] = categories[key] || [] 273 | categories[key].push(repo) 274 | return categories 275 | }, {}) 276 | } 277 | 278 | function reattachCategories(repos, categories) { 279 | const keys = Object.keys(categories) 280 | 281 | repos.forEach(function(repo) { 282 | keys.forEach(function(key) { 283 | const idx = categories[key].indexOf(repo.path) 284 | if (idx !== -1) repo.category = key 285 | }) 286 | }) 287 | 288 | return repos 289 | } 290 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const React = require('react') 2 | 3 | // URL to download the wiki packages list from 4 | exports.wiki = 'https://raw.githubusercontent.com/wiki/stackgl/packages/Packages.md' 5 | exports.home = 'http://stack.gl/' 6 | 7 | // JSX for logo, to be placed at the top of the sidebar 8 | exports.logo = function () { 9 | return

#stackgl

10 | } 11 | -------------------------------------------------------------------------------- /elements/contributor-list.css: -------------------------------------------------------------------------------- 1 | .stackgl-readme .contrib .list { 2 | list-style-type: none; 3 | margin: 0; 4 | padding: 0; 5 | position: absolute; 6 | top: 0; left: 0; right: 0; bottom: 0; 7 | text-align: right; 8 | z-index: 2; 9 | } 10 | 11 | .stackgl-readme .contrib { 12 | position: absolute; 13 | top: 0; 14 | left: 0; 15 | right: 0; 16 | bottom: 0; 17 | overflow: hidden; 18 | } 19 | 20 | .stackgl-readme .contrib .list > li { 21 | display: inline-block; 22 | } 23 | 24 | .stackgl-readme .contrib .list > li:before { 25 | display: none; 26 | content: ''; 27 | } 28 | 29 | .stackgl-readme .contrib .list img { 30 | display: inline-block; 31 | border-radius: 25px; 32 | width: 25px; 33 | height: 25px; 34 | margin-left: 5px; 35 | } 36 | -------------------------------------------------------------------------------- /elements/contributor-list.js: -------------------------------------------------------------------------------- 1 | const React = require('react') 2 | 3 | module.exports = class ContributorList extends React.Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | 8 | render() { 9 | return ( 10 | 21 | ) 22 | } 23 | } 24 | 25 | function shuffle() { 26 | return Math.random() - 0.5 27 | } 28 | -------------------------------------------------------------------------------- /elements/readme-panel.css: -------------------------------------------------------------------------------- 1 | body .stackgl-readme, 2 | body .stackgl-readme pre, 3 | body .stackgl-readme code { 4 | font-family: fantasque; 5 | } 6 | 7 | .panel { 8 | margin-left: 332px; 9 | } 10 | 11 | .panelInner { 12 | padding: 4rem; 13 | max-width: 600px; 14 | } 15 | 16 | .panel .title { 17 | margin-top: 0; 18 | } 19 | .panel .title > a { 20 | background: #fff; 21 | position: relative; 22 | display: inline-block; 23 | z-index: 3; 24 | } 25 | .panel .title > a:after { 26 | content: ''; 27 | z-index: 4; 28 | display: block; 29 | position: absolute; 30 | top: 0; bottom: 0; 31 | left: 100%; 32 | width: 150px; 33 | pointer-events: none; 34 | background: linear-gradient(to right, 35 | rgba(255,255,255,1) 7%, 36 | rgba(255,255,255,0) 100%); 37 | } 38 | 39 | .panel .title .contrib a { 40 | background: transparent; 41 | box-shadow: none; 42 | } 43 | -------------------------------------------------------------------------------- /elements/readme-panel.js: -------------------------------------------------------------------------------- 1 | const ContributorList = require('./contributor-list') 2 | const React = require('react') 3 | const path = require('path') 4 | const fs = require('fs') 5 | 6 | module.exports = class ReadmePanel extends React.Component { 7 | constructor(props) { 8 | super(props) 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 |
15 |
16 | ) 17 | } 18 | 19 | componentDidUpdate() { this.fillReadme(this.props.readme || '') } 20 | componentDidMount() { this.fillReadme(this.props.readme || '') } 21 | 22 | fillReadme(readme) { 23 | const repo = this.props.repo 24 | const el = React.findDOMNode(this.refs.readme) 25 | const node = el.querySelector('.title .contrib') 26 | 27 | if (node) React.unmountComponentAtNode(node) 28 | 29 | el.innerHTML = readme 30 | 31 | if (!repo) return 32 | 33 | React.render( 34 | 35 | , el.querySelector('.title .contrib')) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /elements/repo-list-item.css: -------------------------------------------------------------------------------- 1 | .repoListItem { 2 | font-family: 'fantasque'; 3 | white-space: pre; 4 | margin: 0; 5 | font-size: 0.8rem; 6 | height: 1.5rem; 7 | line-height: 1.5rem; 8 | position: relative; 9 | padding-bottom: 1px; 10 | } 11 | 12 | .itemSelected { 13 | font-weight: bold; 14 | } 15 | 16 | .repoListItem .link { 17 | position: absolute; 18 | top: 0; left: 0; right: 0; bottom: 0; 19 | display: flex; 20 | justify-content: space-between; 21 | text-decoration: none; 22 | } 23 | 24 | .repoListItem .name { 25 | float: left; 26 | color: #777; 27 | } 28 | 29 | 30 | .repoListItem .version { 31 | float: right; 32 | color: #ccc; 33 | } 34 | 35 | .repoListItem .version:before { 36 | content: '@ '; 37 | opacity: 0.5; 38 | } 39 | 40 | .repoListItem:hover { 41 | border-bottom: 1px solid #f2f2f2; 42 | padding-bottom: 0; 43 | } 44 | 45 | .repoListItem:hover .name, 46 | .repoListItem:hover .version { 47 | color: #66C4FF; 48 | } 49 | -------------------------------------------------------------------------------- /elements/repo-list-item.js: -------------------------------------------------------------------------------- 1 | const React = require('react') 2 | 3 | module.exports = class RepoListItem extends React.Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | 8 | render() { 9 | const repo = this.props.repo 10 | const name = {repo.name} 11 | const vers = {repo.version} 12 | 13 | var classes = 'repoListItem' 14 | if (this.props.selected) classes += ' ' + 'itemSelected' 15 | 16 | return ( 17 |
  • 18 | this.handleClick(e)}> 19 | {repo.version ? [name, vers] : name} 20 | 21 |
  • 22 | ) 23 | } 24 | 25 | handleClick(e) { 26 | e.preventDefault() 27 | e.stopPropagation() 28 | window.location.hash = this.props.repo.path 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /elements/repo-list.css: -------------------------------------------------------------------------------- 1 | .repoList { 2 | position: fixed; 3 | top: 0; bottom: 0; 4 | left: 0; 5 | width: 332px; 6 | box-sizing: border-box; 7 | padding: 2.5rem; 8 | background: #fff; 9 | overflow: auto; 10 | overflow-x: hidden; 11 | overflow-y: auto; 12 | border-right: 1px dotted #DEE7FF; 13 | } 14 | 15 | .itemList { 16 | list-style-type: none; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | .categoryList { 22 | list-style-type: none; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | 27 | .repoListInput { 28 | -webkit-appearance: none; 29 | -moz-appearance: none; 30 | appearance: none; 31 | border: 0; 32 | border-bottom: 1px dotted #aaa; 33 | padding: 0.5rem 0; 34 | font-size: 1rem; 35 | font-weight: 100; 36 | background: transparent; 37 | color: #444; 38 | margin-bottom: 1rem; 39 | width: 100%; 40 | font-family: 'fantasque'; 41 | 42 | } 43 | 44 | .repoListInput:focus { 45 | outline: 0; 46 | border-bottom: 1px solid #66C4FF; 47 | } 48 | 49 | .logo { 50 | font-family: 'Roboto'; 51 | text-decoration: none; 52 | } 53 | 54 | .logo h1 { 55 | margin-top: 0; 56 | font-weight: 100; 57 | color: #34363B; 58 | } 59 | 60 | .logo .light { 61 | color: #A9B0C2; 62 | } 63 | 64 | .heading { 65 | font-family: 'Roboto'; 66 | font-size: 1.35rem; 67 | font-weight: 300; 68 | margin-top: 2.5rem; 69 | margin-bottom: 1rem; 70 | } 71 | -------------------------------------------------------------------------------- /elements/repo-list.js: -------------------------------------------------------------------------------- 1 | const fuzz = require('fuzzaldrin').filter 2 | const RepoListItem = require('./repo-list-item') 3 | const config = require('../config') 4 | const React = require('react') 5 | 6 | module.exports = class RepoList extends React.Component { 7 | constructor(props) { 8 | super(props) 9 | this.state = { search: '' } 10 | } 11 | 12 | render() { 13 | var repos = this.props.repos 14 | if (this.state.search) { 15 | var filtered = fuzz(flat(repos), this.state.search, { key: 'path' }) 16 | var content = ( 17 | 23 | ) 24 | } else { 25 | var content = ( 26 | 39 | ) 40 | } 41 | 42 | return ( 43 | 57 | ) 58 | } 59 | 60 | handleChange(e) { 61 | this.setState({ search: e.target.value || '' }) 62 | } 63 | } 64 | 65 | function flat(categories) { 66 | return Object.keys(categories).reduce(function(memo, key) { 67 | return memo.concat(categories[key]) 68 | }, []) 69 | } 70 | -------------------------------------------------------------------------------- /highlight.js: -------------------------------------------------------------------------------- 1 | const Highlights = require('highlights') 2 | const cheerio = require('cheerio') 3 | const languages = { 4 | javascript: require.resolve('language-javascript/package.json'), 5 | bash: require.resolve('language-shellscript/package.json'), 6 | json: require.resolve('language-json/package.json'), 7 | glsl: require.resolve('language-glsl/package.json'), 8 | html: require.resolve('language-html/package.json'), 9 | css: require.resolve('language-css/package.json') 10 | } 11 | 12 | module.exports = highlight 13 | 14 | const highlighter = new Highlights 15 | Object.keys(languages).forEach(function (name) { 16 | return highlighter.requireGrammarsSync({ 17 | modulePath: languages[name] 18 | }) 19 | }) 20 | 21 | function highlight (code, lang, done) { 22 | if (!lang) return done(null, code) 23 | if (lang === 'bash') lang = 'shell' 24 | if (lang === 'sh') lang = 'shell' 25 | if (lang === 'javascript') lang = 'js' 26 | 27 | var result = highlighter.highlightSync({ 28 | fileContents: code.replace(/\n$/g, ''), 29 | scopeName: 'source.' + lang 30 | }) 31 | 32 | result = cheerio.load(result)('.editor').html() 33 | 34 | done(null, result.trim()) 35 | } 36 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} 3 | 4 | pre { 5 | white-space: normal; 6 | } 7 | 8 | body, html { 9 | padding: 0; 10 | margin: 0; 11 | } 12 | 13 | a { 14 | outline: 0; 15 | } 16 | 17 | @import './static/font/index.css'; 18 | @import './elements/contributor-list.css'; 19 | @import './elements/readme-panel.css'; 20 | @import './elements/repo-list-item.css'; 21 | @import './elements/repo-list.css'; 22 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const meta = require('./dist/index.json') 2 | const React = require('react') 3 | const xhr = require('xhr') 4 | const path = require('path') 5 | const fs = require('fs') 6 | 7 | const ReadmePanel = require('./elements/readme-panel') 8 | const RepoList = require('./elements/repo-list') 9 | 10 | const intro = fs.readFileSync( 11 | path.join(__dirname, 'dist', 'intro.html') 12 | , 'utf8') 13 | 14 | require('insert-css')(require('stackgl-readme-css')) 15 | 16 | determineTotalCount(meta) 17 | unindexContributors(meta) 18 | flattenRepoList(meta) 19 | render() 20 | window.addEventListener('hashchange', render) 21 | 22 | function render () { 23 | const repo = String(window.location.hash).slice(1) 24 | const uri = repo + '.json' 25 | const json = true 26 | const repoData = lookupRepo(meta.flat, repo) 27 | 28 | if (uri.length <= 5) return ready(intro) 29 | 30 | xhr({ uri, json }, function (err, res, body) { 31 | if (err) throw err 32 | ready(body.readme) 33 | }) 34 | 35 | function ready (readme) { 36 | React.render( 37 |
    38 | 39 | 40 |
    41 | , document.body) 42 | window.scrollTo(0, 0) 43 | } 44 | } 45 | 46 | function unindexContributors (meta) { 47 | Object.keys(meta.repos).forEach(function (key) { 48 | meta.repos[key].forEach(function (repo) { 49 | repo.path = [repo.user, repo.name].join('/') 50 | repo.contrib = repo.contrib.map(function (i) { 51 | return meta.contributors[i] 52 | }) 53 | }) 54 | }) 55 | } 56 | 57 | function flattenRepoList (meta) { 58 | meta.flat = Object.keys(meta.repos).reduce(function(memo, key) { 59 | return memo.concat(meta.repos[key]) 60 | }, []) 61 | } 62 | 63 | function determineTotalCount (meta) { 64 | meta.count = Object.keys(meta.repos).reduce(function (memo, key) { 65 | return memo + meta.repos[key].length 66 | }, 0) 67 | } 68 | 69 | function lookupRepo (list, path) { 70 | for (var i = 0; i < list.length; i++) { 71 | if (list[i].path === path) { 72 | return list[i] 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /intro.md: -------------------------------------------------------------------------------- 1 | # stack.gl package documentation 2 | 3 | This is a full list of the packages that fall under the 4 | [stack.gl](http://stack.gl) umbrella, catalogued into a single page with all 5 | of their documentation for you to peruse at your leisure. 6 | 7 | You can very easily add your own packages to this list by updating 8 | [the GitHub wiki](http://github.com/stackgl/packages/wiki/Packages/_edit). 9 | You'll see your repository added to the list when it's next updated, which 10 | happens once every hour or so. No need to be shy contributing: the more 11 | the merrier! 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "packages", 3 | "private": true, 4 | "version": "1.0.0", 5 | "scripts": { 6 | "postinstall": "mkdir -p dist && npm run sync && npm run make", 7 | "prestart": "npm run make", 8 | "start": "(watchify index.js -o dist/bundle.js & cssnext -Uw index.css dist/bundle.css & serve ./dist -SJ)", 9 | "predeploy": "browserify index.js | uglifyjs -cm > dist/bundle.js && cssnext -cU index.css dist/bundle.css", 10 | "make": "node build-make", 11 | "sync": "node build-sync" 12 | }, 13 | "engines": { 14 | "npm": "=6.14.4", 15 | "node": "=8.11.4" 16 | }, 17 | "browserify": { 18 | "transform": [ 19 | "reactify", 20 | "babelify", 21 | "brfs" 22 | ] 23 | }, 24 | "dependencies": { 25 | "babelify": "^6.1.2", 26 | "brfs": "^1.4.0", 27 | "browserify": "^10.2.4", 28 | "cheerio": "^0.19.0", 29 | "cpr": "0.4.1", 30 | "css-modulesify": "^0.3.3", 31 | "cssnext": "^1.8.1", 32 | "domify": "^1.3.3", 33 | "ecosystem-docs": "^1.1.0", 34 | "fuzzaldrin": "^2.1.0", 35 | "ghauth": "^4.0.0", 36 | "highlights": "^1.3.0", 37 | "insert-css": "^0.2.0", 38 | "language-css": "atom/language-css", 39 | "language-glsl": "^1.0.0", 40 | "language-html": "atom/language-html", 41 | "language-javascript": "atom/language-javascript", 42 | "language-json": "atom/language-json", 43 | "language-shellscript": "atom/language-shellscript", 44 | "map-limit": "0.0.1", 45 | "marked": "^0.3.3", 46 | "mdast": "^0.22.0", 47 | "mkdirp": "^0.5.1", 48 | "node-jsx": "^0.13.3", 49 | "postcss-import": "^6.1.1", 50 | "pygmentize-bundled": "^2.3.0", 51 | "react": "^0.13.3", 52 | "reactify": "^1.1.1", 53 | "request": "^2.58.0", 54 | "serve": "^1.4.0", 55 | "stackgl-readme-css": "^1.2.0", 56 | "uglify-js": "^2.4.23", 57 | "watchify": "^3.2.2", 58 | "xhr": "^2.0.1" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-Bold.eot -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-Bold.woff -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-BoldItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-BoldItalic.eot -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-BoldItalic.woff -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-RegItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-RegItalic.eot -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-RegItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-RegItalic.woff -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-Regular.eot -------------------------------------------------------------------------------- /static/font/FantasqueSansMono-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/FantasqueSansMono-Regular.woff -------------------------------------------------------------------------------- /static/font/fantasque.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'fantasque'; 3 | src: url('font/FantasqueSansMono-BoldItalic.eot'); /* IE 9 Compatibility Mode */ 4 | src: url('font/FantasqueSansMono-BoldItalic.eot?#iefix') format('embedded-opentype'), /* IE < 9 */ 5 | url('font/FantasqueSansMono-BoldItalic.woff') format('woff'), /* Firefox >= 3.6, any other modern browser */ 6 | url('font/FantasqueSansMono-BoldItalic.ttf') format('truetype'), /* Safari, Android, iOS */ 7 | url('font/FantasqueSansMono-BoldItalic.svg#strippedname:/home/jany/Polices/Cosmic/Sources/FantasqueSansMono-BoldItalic.sfd') format('svg'); /* Chrome < 4, Legacy iOS */ 8 | font-weight: bold; 9 | font-style: italic; 10 | } 11 | @font-face { 12 | font-family: 'fantasque'; 13 | src: url('font/FantasqueSansMono-Bold.eot'); /* IE 9 Compatibility Mode */ 14 | src: url('font/FantasqueSansMono-Bold.eot?#iefix') format('embedded-opentype'), /* IE < 9 */ 15 | url('font/FantasqueSansMono-Bold.woff') format('woff'), /* Firefox >= 3.6, any other modern browser */ 16 | url('font/FantasqueSansMono-Bold.ttf') format('truetype'), /* Safari, Android, iOS */ 17 | url('font/FantasqueSansMono-Bold.svg#strippedname:/home/jany/Polices/Cosmic/Sources/FantasqueSansMono-Bold.sfd') format('svg'); /* Chrome < 4, Legacy iOS */ 18 | font-weight: bold; 19 | font-style: normal; 20 | } 21 | @font-face { 22 | font-family: 'fantasque'; 23 | src: url('font/FantasqueSansMono-RegItalic.eot'); /* IE 9 Compatibility Mode */ 24 | src: url('font/FantasqueSansMono-RegItalic.eot?#iefix') format('embedded-opentype'), /* IE < 9 */ 25 | url('font/FantasqueSansMono-RegItalic.woff') format('woff'), /* Firefox >= 3.6, any other modern browser */ 26 | url('font/FantasqueSansMono-RegItalic.ttf') format('truetype'), /* Safari, Android, iOS */ 27 | url('font/FantasqueSansMono-RegItalic.svg#strippedname:/home/jany/Polices/Cosmic/Sources/FantasqueSansMono-RegItalic.sfd') format('svg'); /* Chrome < 4, Legacy iOS */ 28 | font-weight: normal; 29 | font-style: italic; 30 | } 31 | @font-face { 32 | font-family: 'fantasque'; 33 | src: url('font/FantasqueSansMono-Regular.eot'); /* IE 9 Compatibility Mode */ 34 | src: url('font/FantasqueSansMono-Regular.eot?#iefix') format('embedded-opentype'), /* IE < 9 */ 35 | url('font/FantasqueSansMono-Regular.woff') format('woff'), /* Firefox >= 3.6, any other modern browser */ 36 | url('font/FantasqueSansMono-Regular.ttf') format('truetype'), /* Safari, Android, iOS */ 37 | url('font/FantasqueSansMono-Regular.svg#strippedname:/home/jany/Polices/Cosmic/Sources/FantasqueSansMono-Regular.sfd') format('svg'); /* Chrome < 4, Legacy iOS */ 38 | font-weight: normal; 39 | font-style: normal; 40 | } 41 | -------------------------------------------------------------------------------- /static/font/index.css: -------------------------------------------------------------------------------- 1 | @import './stackgl.css'; 2 | @import './fantasque.css'; 3 | -------------------------------------------------------------------------------- /static/font/stackgl.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'stackgl'; 3 | src: url('font/stackgl.eot?62919735'); 4 | src: url('font/stackgl.eot?62919735#iefix') format('embedded-opentype'), 5 | url('font/stackgl.woff?62919735') format('woff'), 6 | url('font/stackgl.ttf?62919735') format('truetype'), 7 | url('font/stackgl.svg?62919735#stackgl') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 12 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 13 | /* 14 | @media screen and (-webkit-min-device-pixel-ratio:0) { 15 | @font-face { 16 | font-family: 'stackgl'; 17 | src: url('../font/stackgl.svg?62919735#stackgl') format('svg'); 18 | } 19 | } 20 | */ 21 | 22 | [class^="icon-"]:before, [class*=" icon-"]:before { 23 | font-family: "stackgl"; 24 | font-style: normal; 25 | font-weight: normal; 26 | speak: none; 27 | 28 | display: inline-block; 29 | text-decoration: inherit; 30 | width: 1em; 31 | margin-right: .2em; 32 | text-align: center; 33 | /* opacity: .8; */ 34 | 35 | /* For safety - reset parent styles, that can break glyph codes*/ 36 | font-variant: normal; 37 | text-transform: none; 38 | 39 | /* fix buttons height, for twitter bootstrap */ 40 | line-height: 1em; 41 | 42 | /* Animation center compensation - margins should be symmetric */ 43 | /* remove if not needed */ 44 | margin-left: .2em; 45 | 46 | /* you can be more comfortable with increased icons size */ 47 | /* font-size: 120%; */ 48 | 49 | /* Font smoothing. That was taken from TWBS */ 50 | -webkit-font-smoothing: antialiased; 51 | -moz-osx-font-smoothing: grayscale; 52 | 53 | /* Uncomment for 3D effect */ 54 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 55 | } 56 | 57 | .icon-home:before { content: '\e800'; } /* '' */ 58 | .icon-github:before { content: '\e801'; } /* '' */ 59 | .icon-comment:before { content: '\e802'; } /* '' */ 60 | .icon-gift:before { content: '\e803'; } /* '' */ 61 | .icon-star:before { content: '\e806'; } /* '' */ 62 | -------------------------------------------------------------------------------- /static/font/stackgl.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/stackgl.eot -------------------------------------------------------------------------------- /static/font/stackgl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2015 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /static/font/stackgl.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/stackgl.ttf -------------------------------------------------------------------------------- /static/font/stackgl.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stackgl/packages/3665a99837398d85483b0366b66444d24098a63b/static/font/stackgl.woff -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | stackgl/packages 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------