├── .gitignore ├── LICENSE ├── README.markdown ├── TODO ├── coffee └── gcb.coffee ├── css └── style.css ├── html └── badge.html ├── img ├── commit.png └── public.png ├── index.html ├── js └── gcb.js └── scss └── style.scss /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | coffee/config.coffee 3 | js/config.js 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Johannes Gilger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | GitHub Commit Badge 2 | =================== 3 | 4 | This badge/banner can be used for displaying the latest (or a specific 5 | commit) for a GitHub project on your website. It looks like this: 6 | 7 |
GitHub commit badge
8 | 9 | It is implemented in JavaScript, meaning that it is completely client-based. I 10 | recently rewrote this whole project using CoffeeScript and SASS instead of 11 | plain JavaScript and CSS. 12 | 13 | Dependencies 14 | ------------ 15 | 16 | github-commit-badge uses jquery. Many websites/blogs already include it, but if 17 | you don't, then simply add this line to your website: 18 | 19 | 20 | 21 | 22 | Usage 23 | ----- 24 | 25 | To use the badge on your website, upload the 'css', 'html', 'img' and 'js' 26 | directories to your webserver. Then you can spawn badges on your website like 27 | this: 28 | 29 | ``` 30 |
31 | 39 | 40 | 41 |
42 | ``` 43 | 44 | If you want to use it on something like WordPress you'll have to put HTML 45 | quotes around the content of the first script-block 46 | 47 | ``` 48 | 55 | ``` 56 | 57 | Website 58 | ------- 59 | 60 | * http://github.com/heipei/github-commit-badge/tree has the latest version. 61 | * See a working demonstration at http://heipei.net/files/github-commit-badge/ 62 | 63 | FAQ 64 | --- 65 | 66 | **Q**: How does it work? Where does the data come from? 67 | **A**: For each repository, the code will issue two API requests to GitHub to fetch the information. 68 | 69 | **Q**: Why is it called a badge when it's really more of a banner? 70 | **A**: Because I noticed that calling it banner increases the risk of it being filtered by AdBlock etc. 71 | 72 | 73 | Developing 74 | ---------- 75 | 76 | To make changes you should really use [CoffeeScript](http://coffeescript.org/) 77 | and [Sass](http://sass-lang.com/). Simply set up watchers like this: 78 | ``` 79 | sass --watch scss:css 80 | coffee -c --watch -o js coffee 81 | ``` 82 | 83 | Author 84 | ------ 85 | 86 | Johannes Gilger 87 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Include jquery / config.js as needed 2 | - Put everything into subdirs, use CoffeeScript and Sass 3 | - Get rid of stupid 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /js/gcb.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.8.0 2 | (function() { 3 | var Badge, COMMIT_DISPLAYED_ID_LENGTH, COMMIT_MSG_MAX_LENGTH, DEFAULT_BRANCH_NAME, HIDE_FILES_TXT, SHOW_FILES_TXT, commit_msg, config, mainpage, parseDate, truncate; 4 | 5 | config = this; 6 | 7 | config.client_id = ""; 8 | 9 | config.client_secret = ""; 10 | 11 | config.devel = "&client_id=" + client_id + "&client_secret=" + client_secret; 12 | 13 | DEFAULT_BRANCH_NAME = "master"; 14 | 15 | COMMIT_MSG_MAX_LENGTH = 120; 16 | 17 | COMMIT_DISPLAYED_ID_LENGTH = 8; 18 | 19 | SHOW_FILES_TXT = 'Click to show more'; 20 | 21 | HIDE_FILES_TXT = 'Click to show less'; 22 | 23 | truncate = function(string, length, truncation) { 24 | if (length == null) { 25 | length = 30; 26 | } 27 | if (truncation == null) { 28 | truncation = "..."; 29 | } 30 | return string.slice(0, +length + 1 || 9e9); 31 | }; 32 | 33 | commit_msg = function(string) { 34 | var s; 35 | s = truncate(string.replace(/\n/, "").replace(/\r/, ""), COMMIT_MSG_MAX_LENGTH); 36 | console.log(s); 37 | return s; 38 | }; 39 | 40 | parseDate = function(dateTime) { 41 | return dateTime.replace(/T.*/, ""); 42 | }; 43 | 44 | Badge = (function() { 45 | var api_commit, api_repo, commit_url, name, selector; 46 | 47 | selector = api_commit = api_repo = name = commit_url = ""; 48 | 49 | function Badge(username, repo, branch) { 50 | this.username = username; 51 | this.repo = repo; 52 | this.branch = branch != null ? branch : DEFAULT_BRANCH_NAME; 53 | this.api_commit = "https://api.github.com/repos/" + this.username + "/" + this.repo + "/commits/" + this.branch + "?callback=?" + devel; 54 | this.api_repo = "https://api.github.com/repos/" + this.username + "/" + this.repo + "?callback=?" + devel; 55 | this.name = "" + username + "_" + (repo.replace(/\./g, '-')); 56 | this.selector = "#" + this.name; 57 | $("#gcb-template").clone().appendTo("#gcb-container").attr("id", this.name); 58 | $(this.selector).appendTo("#gcb-container").show(); 59 | this.parse_commit(); 60 | this.parse_repo(); 61 | } 62 | 63 | Badge.prototype.parse_commit = function() { 64 | return $.getJSON(this.api_commit, (function(_this) { 65 | return function(data) { 66 | var added, file, modified, removed, _i, _len, _ref; 67 | if (data.meta && data.meta.status === 403) { 68 | console.log("Something went wrong requesting the commits for " + _this.api_commit + ": " + data.data.message); 69 | $(selector).text("Error: " + data.data.message); 70 | return; 71 | } 72 | $("div.diffline img.gravatar", _this.selector).attr({ 73 | "src": data.data.committer.avatar_url + "&s=120", 74 | alt: "" 75 | }); 76 | _this.commit_url = "https://github.com/" + _this.username + "/" + _this.repo + "/commit/" + data.data.sha; 77 | added = removed = modified = 0; 78 | _ref = data.data.files; 79 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 80 | file = _ref[_i]; 81 | switch (file.status) { 82 | case "modified": 83 | modified++; 84 | $("ul.difflist", _this.selector).append($("
  • ").text(file.filename).prepend($("")).append($("").text(" (" + file.changes + ")"))); 85 | break; 86 | case "added": 87 | added++; 88 | $("ul.difflist", _this.selector).append($("
  • ").text(file.filename).prepend($("")).append($("").text(" (" + file.changes + ")"))); 89 | break; 90 | default: 91 | removed++; 92 | $("ul.difflist", _this.selector).append($("
  • ").text(file.filename).prepend($("")).append($("").text(" (" + file.changes + ")"))); 93 | } 94 | } 95 | $("span.branch", _this.selector).html(" (branch: " + _this.branch + ")"); 96 | $("div.diffline a.badge", _this.selector).attr({ 97 | "href": _this.commit_url 98 | }).text(truncate(data.data.sha, COMMIT_DISPLAYED_ID_LENGTH, "")); 99 | $("span.text-date", _this.selector).text(" " + (parseDate(data.data.commit.committer.date))); 100 | $("span.committer", _this.selector).text(data.data.commit.committer.name); 101 | $("span.email", _this.selector).text(" <" + data.data.commit.committer.email + ">"); 102 | $("div.commitmessage", _this.selector).text(data.data.commit.message); 103 | $("a.showMoreLink", _this.selector).attr("id", "showMoreLink_" + _this.name); 104 | $("div.diffstat span.diffadded", _this.selector).before(added); 105 | $("div.diffstat span.diffremoved", _this.selector).before(removed); 106 | $("div.diffstat span.diffmodified", _this.selector).before(modified); 107 | $("div.filelist", _this.selector).attr({ 108 | id: "files_" + _this.name 109 | }); 110 | $("#showMoreLink_" + _this.name).click(function() { 111 | if ($("#showMoreLink_" + _this.name).text() === SHOW_FILES_TXT) { 112 | $("#showMoreLink_" + _this.name).text(HIDE_FILES_TXT); 113 | $("" + _this.selector + " > .commitmessage").css("max-height", "1000px"); 114 | } else { 115 | $("#showMoreLink_" + _this.name).text(SHOW_FILES_TXT); 116 | $("" + _this.selector + " > .commitmessage").css("max-height", "1.2em"); 117 | } 118 | $("#files_" + _this.name).toggle(400); 119 | return false; 120 | }); 121 | return $(_this.selector).click(function() { 122 | return $("#showMoreLink_" + _this.name).click(); 123 | }); 124 | }; 125 | })(this)); 126 | }; 127 | 128 | Badge.prototype.parse_repo = function() { 129 | return $.getJSON(this.api_repo, (function(_this) { 130 | return function(data) { 131 | $("div.username a", _this.selector).text("" + _this.username + "/" + _this.repo).attr("href", data.data.html_url); 132 | $("span.followers", _this.selector).text(data.data.subscribers_count); 133 | $("span.stars", _this.selector).text(data.data.stargazers_count); 134 | return $("span.forks", _this.selector).text(data.data.forks); 135 | }; 136 | })(this)); 137 | }; 138 | 139 | return Badge; 140 | 141 | })(); 142 | 143 | mainpage = function() { 144 | return $("#gcb-container").load("html/badge.html", function() { 145 | var badgeData, _i, _len, _results; 146 | _results = []; 147 | for (_i = 0, _len = Badges.length; _i < _len; _i++) { 148 | badgeData = Badges[_i]; 149 | _results.push(new Badge(badgeData.username, badgeData.repo, badgeData.branch)); 150 | } 151 | return _results; 152 | }); 153 | }; 154 | 155 | $('head').append($('').attr('href', 'css/style.css')); 156 | 157 | $('head').append($('').attr('href', 'https://assets-cdn.github.com/assets/github-4fb2951910292e447b02038004afc1cb52066737eae7585406ec7f5d507810af.css')); 158 | 159 | $(function() { 160 | return mainpage(); 161 | }); 162 | 163 | }).call(this); 164 | -------------------------------------------------------------------------------- /scss/style.scss: -------------------------------------------------------------------------------- 1 | // vim:ft=sass:et:sw=2:ts=2 2 | $color-modified: #d0b44c; 3 | $color-added: #6CC644; 4 | $color-removed: #BD2C00; 5 | 6 | #gcb-container { 7 | width: 580px; 8 | color: #333; 9 | 10 | font: 13px/1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; 11 | 12 | 13 | // outline == container itself 14 | .outline { 15 | border: 1px solid #AAAAAA; 16 | overflow: auto; 17 | margin: 8px; 18 | padding: 5px; 19 | padding-top: 2px; 20 | border-radius: 4px; 21 | background-color: rgb(245, 245, 245); 22 | border-bottom-style: solid; 23 | border-bottom-width: 1px; 24 | box-sizing: border-box; 25 | color: rgb(51, 51, 51); 26 | } 27 | 28 | .username { 29 | margin: 1px 0px 4px 0px; 30 | height: 17px; 31 | color: gray; 32 | } 33 | 34 | .diffline { 35 | font-weight: normal; 36 | font-size: 14px; 37 | } 38 | 39 | .commitmessage { 40 | font-style: italic; 41 | margin-top: 5px; 42 | margin-bottom: 5px; 43 | line-height: 1.2em; 44 | max-height: 1.2em; 45 | -webkit-transition: max-height 1s ease; 46 | -moz-transition: max-height 1s ease; 47 | transition: max-height 1s ease; 48 | overflow: hidden; 49 | white-space: pre; 50 | .octicon { 51 | margin-right: 5px; 52 | opacity: 0.5; 53 | } 54 | } 55 | 56 | .quote { 57 | margin: 0px 5px 0px 5px; 58 | float: left; 59 | } 60 | 61 | 62 | .diffstat { 63 | font-weight: normal; 64 | } 65 | 66 | .badge { 67 | color: gray; 68 | font: 13px normal 'Droid Sans Mono', 'Consolas', 'Lucida Console', 'Courier New', monospace; 69 | } 70 | 71 | .username a { 72 | color: #4183C4; 73 | text-decoration: none; 74 | } 75 | 76 | .text-date { 77 | color: #C44040; 78 | } 79 | 80 | .committer { 81 | color: #43651F; 82 | } 83 | 84 | .email { 85 | color: #69A031; 86 | font-weight: normal; 87 | } 88 | 89 | span.diffadded { 90 | color: $color-added; 91 | } 92 | span.diffremoved { 93 | color: $color-removed; 94 | } 95 | span.diffmodified { 96 | color: $color-modified; 97 | } 98 | 99 | .gravatar { 100 | border: 1px solid #aaaaaa; 101 | border-radius: 6px; 102 | float: left; 103 | margin: 2px 5px 2px 2px; 104 | width: 60px; 105 | } 106 | 107 | .filelist { 108 | margin-top: 15px; 109 | ul { 110 | li { 111 | margin-left: 5px; 112 | span { 113 | margin-right: 5px; 114 | &.octicon-diff-added { 115 | color: $color-added; 116 | } 117 | &.octicon-diff-removed { 118 | color: $color-removed; 119 | } 120 | &.octicon-diff-modified { 121 | color: $color-modified; 122 | } 123 | } 124 | } 125 | list-style: none; 126 | margin: 0; 127 | } 128 | } 129 | 130 | .showMore { 131 | display: inline; 132 | float: right; 133 | margin-top: -18px; 134 | opacity: 0.5; 135 | } 136 | 137 | div.outline:hover .showMore { 138 | display: inline; 139 | } 140 | 141 | a { 142 | font-weight: bold; 143 | } 144 | 145 | .username a:hover, 146 | .badge:hover, 147 | .showMoreLink:hover { 148 | text-decoration: none; 149 | } 150 | } 151 | --------------------------------------------------------------------------------