├── .gitignore ├── CHANGELOG.md ├── Gruntfile.js ├── MIT-LICENTSE.txt ├── README.md ├── bin └── octocard.js ├── images ├── favicon.ico ├── logo.png ├── screenshot.png └── updatecode.png ├── index.html ├── package.json ├── src ├── autorun.js ├── loader.js ├── main.js ├── module │ ├── base.js │ ├── details.js │ ├── eventsStatis.js │ ├── footer.js │ ├── orgs.js │ ├── repos.js │ └── stats.js ├── modules.js └── util.js ├── theme.html └── themes ├── azzura-black.less ├── azzura.less ├── base.less ├── clean.less ├── default.less ├── highcontrast.less ├── modern.less ├── night.less └── twitter-widget-dark.css /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | lcov.info 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | 11 | pids 12 | logs 13 | results 14 | build 15 | .grunt 16 | 17 | node_modules 18 | *.swp 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | --- 3 | 4 | - 1.0.0 5 | * init 6 | - 1.0.1 7 | * Fixed #1, supported `reposIgnored` config. 8 | * Fixed README.md: https://github.com/zmmbreeze/octocard/commit/7e840f0631913ead48401be7a4228452832bec74#diff-04c6e90faac2675aa89e2176d2eec7d8L12 9 | - 1.1.0 10 | * Fixed #4, #6 11 | * Fixed #5, default style add background-color 12 | * Fixed #8, support using `shadow dom` or `iframe` to create isolated container 13 | * Added `noIsolated` config 14 | * `public_gists` => `gists` 15 | * Fixed default theme's base module 16 | - 1.2.0 17 | * Fixed #10 #11 #13 18 | * Fixed iphone/ipad iframe width bug 19 | * Added data config 20 | * Updated base module style when loginName is equal to username 21 | * Supported responsive design, added min and max style 22 | * Added repo number to stats module 23 | * Clear useless code 24 | - 1.3.0 25 | * Fixed repo style on min style 26 | * Removed global variable `root` 27 | * Fixed #17, #18, #19 28 | - 1.4.0 29 | * Rebuild themes by less 30 | * Add new themes: azzura-black, azzura, base, clean, highcontrast, modern, night 31 | * Add new config `theme` 32 | - 1.4.1 33 | * Added config `themeCSS` 34 | * Added `theme.html` to make it more easier to build theme; 35 | - 1.4.2 36 | * Support `HTTPS` 37 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * @param {Function} grunt . 5 | */ 6 | module.exports = function(grunt) { 7 | var dest = grunt.option('dest'); 8 | 9 | grunt.initConfig({ 10 | pkg: grunt.file.readJSON('package.json'), 11 | dest: dest || 'bin/', 12 | concat: { 13 | options: { 14 | separator: '\n', 15 | banner: '(function() {\n// This file concat by grunt. \n\n', 16 | footer: '\n})();' 17 | }, 18 | dist: { 19 | src: [ 20 | 'src/autorun.js', 21 | 'src/util.js', 22 | 'src/loader.js', 23 | 'src/modules.js', 24 | 'src/module/*.js', 25 | 'src/main.js' 26 | ], 27 | dest: 'src/octocard.js' 28 | } 29 | }, 30 | uglify: { 31 | options: { 32 | banner: '/*!\n octocard\n' + 33 | ' <%= pkg.version %>\n' + 34 | ' <%= grunt.template.today("dd-mm-yyyy") %>\n*/\n' 35 | }, 36 | dist: { 37 | files: { 38 | 'bin/octocard.js': ['<%= concat.dist.dest %>'] 39 | } 40 | } 41 | }, 42 | jshint: { 43 | files: ['src/**/*.js'], 44 | options: { 45 | globals: { 46 | }, 47 | laxbreak: true, 48 | scripturl: true 49 | } 50 | }, 51 | watch: { 52 | files: ['<%= jshint.files %>'], 53 | tasks: ['jshint'] 54 | }, 55 | clean: [ 56 | 'src/octocard.js', 57 | ], 58 | less: { 59 | options: { 60 | paths: ['themes'], 61 | cleancss: true 62 | }, 63 | files: { 64 | expand: true, 65 | cwd: 'themes/', 66 | src: '*.less', 67 | dest: '<%= dest %>/themes/', 68 | ext: '.css' 69 | } 70 | } 71 | }); 72 | 73 | grunt.loadNpmTasks('grunt-contrib-uglify'); 74 | grunt.loadNpmTasks('grunt-contrib-jshint'); 75 | grunt.loadNpmTasks('grunt-contrib-watch'); 76 | grunt.loadNpmTasks('grunt-contrib-concat'); 77 | grunt.loadNpmTasks('grunt-contrib-clean'); 78 | grunt.loadNpmTasks('grunt-contrib-less'); 79 | 80 | grunt.registerTask('debug', ['clean', 'jshint', 'concat']); 81 | grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'clean']); 82 | grunt.registerTask('theme', ['less']); 83 | }; 84 | 85 | -------------------------------------------------------------------------------- /MIT-LICENTSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 mzhou, http://octocard.in/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Octocard](./images/logo.png) 2 | 3 | Highly flexible github info card for every github lover. And it's open source. Please feel free to fork and build your own Octocard. 4 | 5 | > Octocard now using a new domain name octocard.in! The old domain was stolen, so for safety concern please update the code like this: 6 | > ![screenshot](./images/updatecode.png) 7 | > Really sorry for this, and thank you for your support. 8 | 9 | ![screenshot](./images/screenshot.png) 10 | 11 | - [HOW TO USE](https://github.com/zmmbreeze/octocard/wiki/HOW-TO-USE) 12 | - [Customize theme](https://github.com/zmmbreeze/octocard/wiki/Customize-theme) 13 | 14 | Server part 15 | --- 16 | Octocard works on node server. You can use [octocard.in](http://octocard.in/). It's free. But if you want to build your own server, checkout [server part](https://github.com/zmmbreeze/octocard-server). 17 | 18 | -------------------------------------------------------------------------------- /bin/octocard.js: -------------------------------------------------------------------------------- 1 | /*! 2 | octocard 3 | 1.4.2 4 | 08-12-2016 5 | */ 6 | !function(){var a,b,c,d="e3dfd93b0a15118dd0f9c73013a6b2e9",e=window.octocard&&window.octocard.octocard===d,f=document.getElementsByTagName("script"),g=f[f.length-1];if(g&&g.getAttribute("data-name"))c=!1,b=!0;else if("object"==typeof OCTOCARD&&OCTOCARD.name)c=!0,b=!0;else{if(e)return;b=!1}a={name:"",modules:"",theme:"",reposNum:"",reposIgnored:"",orgsNum:"",element:"",api:"",noIsolated:!1,noFooter:!1,themeCSS:""};for(var h in a)c?a[h]=OCTOCARD[h]:a[h]=g.getAttribute("data-"+h);if(b&&e)return!a.element&&document.getElementById("octocard")&&(a.element="octocard"+(new Date).getTime()),void window.octocard(a);var i=/(\d{4})-(\d{2})-(\d{2})T/,j={createStyle:function(a){var b=document.createElement("style");return b.type="text/css",b.styleSheet?b.styleSheet.cssText=a:b.appendChild(document.createTextNode(a)),b},format:function(a,b,c){if(!b)return a;var d;if("object"!=typeof b){var e=c?b:"#{v}";return d=c||b,a.replace(new RegExp(e,"g"),""+d)}var f=b;return a.replace(c||/#\{([^{}]+)\}/g,function(a,b){return d=f[b],null==d?"":""+d})},jsonp:function(a,b,c){var d,e=document.createElement("script"),f="githubcardjsonp"+(new Date).getTime(),g=5e4,h=0,i=!1,j=a.match(/[?&]callback=([^$&]+)/);j?e.src=a.replace(/([?&]callback=)[^$&]+/,"$1"+f):e.src=a+(a.indexOf("?")===-1?"?":"&")+"callback="+f,e.type="text/javascript",e.charset="UTF-8",window[f]=function(a){return a.success?(i=!0,b(a.data),void(window[f]=null)):(c(a.message),void(i=!0))};var k=function(){!i&&c&&c("Server or network error."),e.onload=e.onreadystatechange=null,document.body.removeChild(e)};e.onload=e.onreadystatechange=function(){if(!h){var a=e.readyState;"undefined"!=typeof a&&"loaded"!=a&&"complete"!=a||(h=1,k(),clearTimeout(d))}},d=setTimeout(function(){k(),window[f]=function(){}},g),document.body.appendChild(e)},bind:function(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},resetTime:function(a){return a.setMilliseconds(0),a.setMinutes(0),a.setHours(0),a.setSeconds(0),a},today:function(){return j.resetTime(new Date)},nextDay:function(a){return new Date(a.getTime()+864e5)},tomorrow:function(){return j.nextDay(j.today())},strToDate:function(a){var b=a.match(i);return new Date(b[1],b[2]-1,b[3],0,0,0,0)},getPageHeight:function(a){var b="scrollHeight",c="offsetHeight",d=a.documentElement,e=a.body;return Math.max(e[b],e[c],d[b],d[c])},getShadowRoot:function(a){for(var b,c=["","webkit","moz","ms"],d=0,e=c.length;d=d&&(e

#{name}

#{_login}',n.add("base",o);var p=function(a,b){var c=a.data.base;if(c.email||c.blog||c.bio||c.location||c.company){var d="";a.appendModHTML("details",d)}b()};n.add("details",p);var q=function(a,b){var c=a.data.eventsStatis;if(0===c.length)return void b();for(var d,e,f,g=0,h=c.length-1,i=[],k=function(a){for(e=new Date(864e5+e.getTime());e=0&&(d=c[h],g=Math.max(g,d.counter),e=j.strToDate(d.date),i.push({date:e,counter:d.counter}),0!==h);h--)f=j.strToDate(c[h-1].date),k(f);var l=j.tomorrow();k(l);var m="";h=i.length-1;for(var n=100/(h+1);h>=0;h--)d=i[h],m+=j.format(q.MOD_BAR_HTML,{date:d.date.toDateString(),counter:d.counter,width:n,height:d.counter/g*100,visibility:d.counter?"visible":"hidden"});a.appendModHTML("eventsStatis",j.format(q.MOD_HTML,{map:m})),b()};q.MOD_HTML='

Events

#{map}
Now
',q.MOD_BAR_HTML='
#{date} - #{counter}
',n.add("eventsStatis",q);var r=function(a,b){var c=a.config.noFooter;if(c&&"false"!==c)return void b();var d=document.createElement("a");d.href="http://octocard.in/",d.target="_blank",d.className="octocard-footer",d.innerHTML="Octocard.in",a.element.appendChild(d),b()};n.add("footer",r);var s=function(a,b){var c=a.data.orgs;if(0===c.length)return void b();var d=parseInt(a.config.orgsNum,10)||-1;d>=0&&(c=c.slice(0,d));for(var e="",f=0,g=c.length;fOrganizations
    #{v}
",s.MOD_LI_HTML='
  • #{login}
  • ',n.add("orgs",s);var t=function(a,b){var c,d;if(data=a.data.repos,0===data.length)return void b();data.sort(function(a,b){return b.watchers_count-a.watchers_count});var e=a.config.reposIgnored,f={};if(e)for(e=e.split(","),c=0,d=e.length;c";for(c=0,g=0,d=data.length;c",a.appendModHTML("repos",i),b()};t.MOD_LI_HTML='
  • #{name}

    #{description}

    #{watchers_count}✭
  • ',n.add("repos",t);var u=function(a,b){var c=j.format(u.MOD_HTML,a.data.base);a.appendModHTML("stats",c),b()};u.MOD_HTML='',n.add("stats",u);var v=function(a){this.reload(a)};v.prototype.reload=function(a){var b=this;b.host&&(b.host.innerHTML=""),a=a||{},b.config=a,a.api=a.api||location.protocol+"//octocard.in/api",b.element=a.element||"octocard","string"==typeof b.element?(b.elementId=b.element,b.element=document.getElementById(b.element),b.element||(b.element=document.createElement("div"),b.element.id=b.elementId,g.parentNode.insertBefore(b.element,g))):b.element.id?b.elementId=b.element.id:(b.elementId="octocard"+(new Date).getTime(),b.element.id=b.elementId),b.host=b.element,a.noIsolated&&"false"!==a.noIsolated||b._createContainer(),b._bindSizeClass(),b.createStyle(function(c){b.element.appendChild(c),b.username=a.name;var d=a.modules||"base,details,stats,repos,eventsStatis,orgs";d=d.split(","),d.unshift("footer"),b.setupModules(d)})},v.prototype._showErrorMsg=function(a,b){var c=document.createElement("div");if(c.className="octocard-error",c.innerHTML=a,b){var d=this,e=document.createElement("a");e.href="javascript:void(0)",e.innerHTML="Refresh",j.bind(e,"click",function(){d.element.removeChild(c),d._updateContainer(),d.setupModules(b)}),c.appendChild(e)}this.element.appendChild(c),this._updateContainer()},v.prototype.loadModule=function(a,b){var c=n.get(a);c&&c(this,b)},v.prototype.appendModHTML=function(a,b){var c=document.createElement("div");return c.className="octocard-m octocard-m-"+a.toLowerCase(),c.innerHTML=b,this.element.appendChild(c),c},v.prototype.createStyle=function(a){var b=this,c=b.config.themeCSS,d=function(a,c){return j.createStyle(j.format(a,"#root-id","#"+b.elementId))};if(c)return void a(d(c,b.elementId));var e=b.config.theme;j.jsonp(b.config.api+"?dataType=theme&name="+(e||""),function(c){a(d(c.css,b.elementId))},function(a){b._showErrorMsg(a)})},v.prototype.setupModules=function(a,b){function c(c){function f(){d.loadModule(a[g],function(){g++,g 2 | 3 | 4 | 5 | octocard 6 | 7 | 8 | 9 | 10 | 38 | 59 | 60 | 68 | 69 | 70 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "octocard", 3 | "version": "1.4.2", 4 | "description": "Highly flexible github info card for every github lover.", 5 | "preferGlobal": true, 6 | "directories": { 7 | "lib": "./src", 8 | "bin": "./bin" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/zmmbreeze/octocard.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/zmmbreeze/octocard/issues" 16 | }, 17 | "keywords": [ 18 | "octocard", 19 | "github", 20 | "card" 21 | ], 22 | "author": "MZhou (http://mzhou.me)", 23 | "license": { 24 | "type": "MIT", 25 | "url": "https://raw.github.com/zmmbreeze/octocard/master/MIT-LICENTSE.txt" 26 | }, 27 | "dependencies": {}, 28 | "devDependencies": { 29 | "grunt": "~0.4.1", 30 | "grunt-contrib-clean": "*", 31 | "grunt-contrib-concat": "*", 32 | "grunt-contrib-jshint": "*", 33 | "grunt-contrib-less": "^0.12.0", 34 | "grunt-contrib-uglify": "*", 35 | "grunt-contrib-watch": "*" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/autorun.js: -------------------------------------------------------------------------------- 1 | // autorun Octocard 2 | var MARK = 'e3dfd93b0a15118dd0f9c73013a6b2e9'; 3 | var isLoadedBefore = window.octocard && window.octocard.octocard === MARK; 4 | var autorunConfig; 5 | // get config from script tag 6 | // eg: 7 | // 19 | var scripts = document.getElementsByTagName('script'); 20 | var lastScript = scripts[scripts.length - 1]; 21 | var hasConfig; // has config 22 | var useOctocardConfig; // use OCTOCARD as config 23 | if (lastScript && lastScript.getAttribute('data-name')) { 24 | // Use attribute 25 | useOctocardConfig = false; 26 | hasConfig = true; 27 | } else if (typeof OCTOCARD === 'object' && OCTOCARD.name) { 28 | useOctocardConfig = true; 29 | hasConfig = true; 30 | } else if (isLoadedBefore) { 31 | // if no config found and octocard was loaded before 32 | return; 33 | } else { 34 | // if no config found and octocard not loaded 35 | hasConfig = false; 36 | } 37 | 38 | autorunConfig = { 39 | name: '', 40 | modules: '', 41 | theme: '', 42 | reposNum: '', 43 | reposIgnored: '', 44 | orgsNum: '', 45 | element: '', 46 | api: '', 47 | noIsolated: false, 48 | noFooter: false, 49 | themeCSS: '' 50 | }; 51 | for (var key in autorunConfig) { 52 | if (useOctocardConfig) { 53 | autorunConfig[key] = OCTOCARD[key]; 54 | } 55 | else { 56 | autorunConfig[key] = lastScript.getAttribute('data-' + key); 57 | } 58 | } 59 | 60 | if (hasConfig && isLoadedBefore) { 61 | // if octocard was included already, 62 | // then create a new octocard. 63 | if (!autorunConfig.element && document.getElementById('octocard')) { 64 | // if id octocard was used, use `octocard + timeString`. 65 | autorunConfig.element = 'octocard' + new Date().getTime(); 66 | } 67 | window.octocard(autorunConfig); 68 | return; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/loader.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | var LOADER_HTML = '' 4 | + '
    ' 5 | + '
    ' 6 | + '
    ' 7 | + '
    ' 8 | + '
    '; 9 | 10 | /** 11 | * Loader 12 | * 13 | * @constructor 14 | * @param {Element} element . 15 | * @param {number} zIndex . 16 | */ 17 | var Loader = function (element, zIndex) { 18 | this.element = element; 19 | 20 | // create and append loader root 21 | var loaderRoot = document.createElement('div'); 22 | loaderRoot.style.zIndex = zIndex || 9; 23 | loaderRoot.className = 'octocard-loading'; 24 | this.element.appendChild(loaderRoot); 25 | this.root = loaderRoot; 26 | 27 | // init html and css 28 | loaderRoot.innerHTML = LOADER_HTML; 29 | 30 | this.highlightNum = 2; 31 | this.start(); 32 | }; 33 | 34 | /** 35 | * start loading animation. 36 | */ 37 | Loader.prototype.start = function () { 38 | var nodes = this.root.firstChild.childNodes; 39 | var that = this; 40 | 41 | this.timer = setInterval(function() { 42 | var highlightNum = that.highlightNum; 43 | nodes[highlightNum].className = '' + 44 | 'octocard-loading-' + highlightNum; 45 | that.highlightNum = highlightNum = (highlightNum + 1) % 3; 46 | nodes[highlightNum].className = '' + 47 | 'octocard-loading-' + highlightNum + 48 | ' octocard-loading-cur'; 49 | }, 500); 50 | }; 51 | 52 | /** 53 | * stop loading animation. 54 | */ 55 | Loader.prototype.stop = function () { 56 | clearInterval(this.timer); 57 | }; 58 | 59 | /** 60 | * end loading animation. 61 | */ 62 | Loader.prototype.end = function () { 63 | this.stop(); 64 | if (this.root) { 65 | this.element.removeChild(this.root); 66 | delete this.root; 67 | } 68 | }; 69 | 70 | var loader = function (element, zIndex) { 71 | return new Loader(element, zIndex); 72 | }; 73 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true, scripturl:true */ 2 | 3 | /** 4 | * Github card 5 | * 6 | * @constructor 7 | * @param {Object=} config 8 | */ 9 | var Octocard = function (config) { 10 | this.reload(config); 11 | }; 12 | 13 | /** 14 | * Reload card. 15 | * 16 | * @param {Object=} config 17 | * OCTOCARD = { 18 | * // [required][string] 19 | * // username 20 | * name: 'zmmbreeze', 21 | * // [optional][string|Element] 22 | * // element or elementId, 'octocard' as default 23 | * element: 'octocard', 24 | * // [optional][string] 25 | * // module names, default is 26 | * // 'base,details,stats,repos,eventsStatis,orgs' 27 | * modules: 'base', 28 | * // [optional][string]specify the theme name to be used 29 | * // 'default' as default 30 | * theme: "azzura", 31 | * // [optional][number]number of organizations to show 32 | * // 'Infinity' as default, show all organizations 33 | * orgsNum: -1, 34 | * // [optional][number]number of repos to show 35 | * // '3' as default 36 | * reposNum: 3, 37 | * // [optional][number]repos which will not be shown 38 | * // '' as default 39 | * reposIgnored: 'reponame1,reponame2', 40 | * // [optional][string]url of jsonp api 41 | * // 'https://octocard.in/api' as default 42 | * api: 'http://your-octocard.com/api', 43 | * // [optional][boolean]show footer or not 44 | * // 'false' as default 45 | * noFooter: false, 46 | * // [optional][boolean] 47 | * // Use `shadowDom/iframe` to create isolate container or not 48 | * // 'false' as default 49 | * data-noIsolated="true" 50 | * } 51 | */ 52 | Octocard.prototype.reload = function (config) { 53 | var that = this; 54 | if (that.host) { 55 | // loaded before 56 | that.host.innerHTML = ''; 57 | } 58 | 59 | config = config || {}; 60 | that.config = config; 61 | 62 | config.api = config.api || (location.protocol + '//octocard.in/api'); 63 | 64 | // setup element & elementId 65 | that.element = config.element || 'octocard'; 66 | if (typeof that.element === 'string') { 67 | that.elementId = that.element; 68 | that.element = document.getElementById(that.element); 69 | if (!that.element) { 70 | that.element = document.createElement('div'); 71 | that.element.id = that.elementId; 72 | lastScript.parentNode.insertBefore(that.element, lastScript); 73 | } 74 | } else { 75 | if (that.element.id) { 76 | that.elementId = that.element.id; 77 | } else { 78 | that.elementId = 'octocard' + new Date().getTime(); 79 | that.element.id = that.elementId; 80 | } 81 | } 82 | 83 | that.host = that.element; 84 | // create isolated container if needed 85 | if (!config.noIsolated || config.noIsolated === 'false') { 86 | that._createContainer(); 87 | } 88 | 89 | that._bindSizeClass(); 90 | 91 | // setup style 92 | that.createStyle(function (styleElement) { 93 | that.element.appendChild(styleElement); 94 | 95 | // setup username & type 96 | that.username = config.name; 97 | // that.type = config.type || 'user'; 98 | 99 | // setup modules 100 | var moduleNames = config.modules || 101 | 'base,details,stats,repos,eventsStatis,orgs'; 102 | moduleNames = moduleNames.split(','); 103 | moduleNames.unshift('footer'); 104 | that.setupModules(moduleNames); 105 | }); 106 | 107 | }; 108 | 109 | /** 110 | * Show load error message. 111 | * 112 | * @param {Array.=} moduleNames module names. 113 | */ 114 | Octocard.prototype._showErrorMsg = function (msg, moduleNames) { 115 | var errorRoot = document.createElement('div'); 116 | errorRoot.className = 'octocard-error'; 117 | errorRoot.innerHTML = msg; 118 | 119 | if (moduleNames) { 120 | var that = this; 121 | var reloadLink = document.createElement('a'); 122 | reloadLink.href = 'javascript:void(0)'; 123 | reloadLink.innerHTML = 'Refresh'; 124 | util.bind(reloadLink, 'click', function () { 125 | that.element.removeChild(errorRoot); 126 | that._updateContainer(); 127 | that.setupModules(moduleNames); 128 | }); 129 | errorRoot.appendChild(reloadLink); 130 | } 131 | 132 | this.element.appendChild(errorRoot); 133 | this._updateContainer(); 134 | }; 135 | 136 | /** 137 | * load module. 138 | * 139 | * @param {string} name module name. 140 | * @param {Function} callback . 141 | */ 142 | Octocard.prototype.loadModule = function (name, callback) { 143 | var m = modules.get(name); 144 | if (m) { 145 | m(this, callback); 146 | } 147 | }; 148 | 149 | /** 150 | * append module html. 151 | * 152 | * @param {string} name module name. 153 | * @param {string} html html string. 154 | */ 155 | Octocard.prototype.appendModHTML = function (name, html) { 156 | var modRoot = document.createElement('div'); 157 | // make sure className is lowercase, because of safari's bug 158 | // http://jsbin.com/yafog/3/edit 159 | modRoot.className = 'octocard-m octocard-m-' + name.toLowerCase(); 160 | modRoot.innerHTML = html; 161 | this.element.appendChild(modRoot); 162 | 163 | return modRoot; 164 | }; 165 | 166 | /** 167 | * create CSS style, and replace '#{id}' to elementId. 168 | * 169 | * @param {function(Element)} complete 170 | * @return {Element} style element. 171 | */ 172 | Octocard.prototype.createStyle = function (complete) { 173 | var that = this; 174 | var themeCSS = that.config.themeCSS; 175 | var createStyle = function (css, elementId) { 176 | return util.createStyle( 177 | util.format(css, '#root-id', '#' + that.elementId) 178 | ); 179 | }; 180 | 181 | if (themeCSS) { 182 | // use local css 183 | complete(createStyle(themeCSS, that.elementId)); 184 | return; 185 | } 186 | 187 | // use remote css 188 | var themeName = that.config.theme; 189 | util.jsonp( 190 | that.config.api 191 | + '?dataType=theme' 192 | + '&name=' + (themeName || ''), 193 | function (data) { 194 | complete(createStyle(data.css, that.elementId)); 195 | }, 196 | function (msg) { 197 | that._showErrorMsg(msg); 198 | } 199 | ); 200 | }; 201 | 202 | /** 203 | * setup modules. 204 | * 205 | * @param {Array.} moduleNames . 206 | * @param {Function} callback . 207 | */ 208 | Octocard.prototype.setupModules = function (moduleNames, callback) { 209 | var that = this; 210 | 211 | if (that.config.data) { 212 | load(that.config.data); 213 | return; 214 | } 215 | 216 | // loading 217 | var l = loader(this.element); 218 | that._updateContainer(); 219 | 220 | // load basic info and modules 221 | util.jsonp( 222 | this.config.api 223 | + '?mods=' + moduleNames.join(',') 224 | + '&login=' + this.username, 225 | load, 226 | // error 227 | function (msg) { 228 | if (l) { 229 | l.end(); 230 | } 231 | that._showErrorMsg(msg, moduleNames); 232 | } 233 | ); 234 | 235 | // success 236 | function load(data) { 237 | that.data = data; 238 | 239 | // start loading modules in turn 240 | var i = 0; 241 | var length = moduleNames.length; 242 | function startLoadModule() { 243 | that.loadModule(moduleNames[i], function () { 244 | i++; 245 | if (i < length) { 246 | startLoadModule(); 247 | } else { 248 | if (l) { 249 | l.end(); 250 | } 251 | that._updateContainer(); 252 | if (callback) { 253 | callback(); 254 | } 255 | } 256 | }); 257 | } 258 | startLoadModule(); 259 | } 260 | }; 261 | 262 | 263 | /** 264 | * create isolated container 265 | */ 266 | Octocard.prototype._createContainer = function () { 267 | var trueRoot = document.createElement('div'); 268 | // if using shadow dom, same id will cause bug on opera 18.0 269 | this.elementId += new Date().getTime(); 270 | trueRoot.id = this.elementId; 271 | 272 | var shadowRoot = util.getShadowRoot(this.element); 273 | if (shadowRoot) { 274 | // support shadow root 275 | shadowRoot.appendChild(trueRoot); 276 | } else { 277 | var iframe = document.createElement('iframe'); 278 | iframe.style.cssText = 'width:100%;height:0;' 279 | + 'position:relative;top:0;left:0;right:0;bottom:0;' 280 | + 'display:block;padding:0;margin:0;border:none;'; 281 | iframe.frameBorder = '0'; 282 | this.element.appendChild(iframe); 283 | var doc = iframe.contentDocument || iframe.contentWindow.document; 284 | doc.open(); 285 | doc.write(''); 286 | doc.close(); 287 | 288 | doc.body.style.cssText = 'overflow:hidden;margin:0;padding:0;'; 289 | doc.body.appendChild(trueRoot); 290 | this.doc = doc; 291 | this.iframe = iframe; 292 | } 293 | 294 | this.isIsolated = true; 295 | this.element = trueRoot; 296 | }; 297 | 298 | /** 299 | * update container height and width 300 | */ 301 | Octocard.prototype._updateContainer = function () { 302 | if (this.iframe) { 303 | var ua = navigator.userAgent; 304 | if((ua.match(/iPhone/i)) || (ua.match(/iPad/i))) { 305 | // Fixed iphone iframe bug 306 | // update container width 307 | var containerWidth = this.iframe.parentNode.offsetWidth; 308 | this.doc.body.style.width = containerWidth + 'px'; 309 | } 310 | // update iframe height 311 | var h = util.getPageHeight(this.doc); 312 | this.iframe.style.height = h + 'px'; 313 | } 314 | }; 315 | 316 | /** 317 | * Bind size class. 318 | */ 319 | Octocard.prototype._bindSizeClass = function () { 320 | var me = this; 321 | util.addSizeClass(me.host, me.element); 322 | 323 | if (me._binded) { 324 | return; 325 | } 326 | me._binded = true; 327 | 328 | var timeout; 329 | util.bind(window, 'resize', function resize() { 330 | if (timeout) { 331 | clearTimeout(timeout); 332 | } 333 | 334 | timeout = setTimeout(function () { 335 | util.addSizeClass(me.host, me.element); 336 | }, 250); 337 | }); 338 | }; 339 | 340 | /** 341 | * create octocard instance 342 | * 343 | * @param {Object} config . 344 | */ 345 | window.octocard = function (config) { 346 | return new Octocard(config); 347 | }; 348 | window.octocard.octocard = MARK; 349 | 350 | if (hasConfig) { 351 | // `name` is required as config 352 | new Octocard(autorunConfig); 353 | } 354 | -------------------------------------------------------------------------------- /src/module/base.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * Base module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var baseModule = function (card, callback) { 10 | var base = card.data.base; 11 | if (!base.name || base.name === base.login) { 12 | // If no name was set or name is login name 13 | // then only show login name. 14 | base.name = base.name || base.login; 15 | base._nameClass = 'octocard-m-base-noname'; 16 | } else { 17 | base._login = base.login; 18 | } 19 | var html = util.format(baseModule.MOD_HTML, card.data.base); 20 | card.appendModHTML('base', html); 21 | callback(); 22 | }; 23 | 24 | baseModule.MOD_HTML = '' 25 | + '' 26 | + '' 27 | + '

    #{name}

    ' 28 | + '#{_login}' 29 | + '
    '; 30 | 31 | modules.add('base', baseModule); 32 | -------------------------------------------------------------------------------- /src/module/details.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * Details module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var detailsModule = function (card, callback) { 10 | var data = card.data.base; 11 | if (data.email || data.blog || data.bio || data.location || data.company) { 12 | var html = '' 13 | + '
      ' 14 | + (data.email ? ('
    • ' + data.email + '
    • ') : '') 15 | + (data.blog 16 | ? ('
    • ' + data.blog + '
    • ') 17 | : '') 18 | + (data.bio ? ('
    • ' + data.bio + '
    • ') : '') 19 | + (data.location ? ('
    • ' + data.location + '
    • ') : '') 20 | + (data.company ? ('
    • ' + data.company + '
    • ') : '') 21 | + '
    '; 22 | card.appendModHTML('details', html); 23 | } 24 | callback(); 25 | }; 26 | 27 | modules.add('details', detailsModule); 28 | 29 | -------------------------------------------------------------------------------- /src/module/eventsStatis.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * eventsStatis module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var eventsStatisModule = function (card, callback) { 10 | var data = card.data.eventsStatis; 11 | 12 | // if input user has no Organization, 13 | // don't show this module 14 | if (data.length === 0) { 15 | callback(); 16 | return; 17 | } 18 | 19 | var d; 20 | 21 | // organize data 22 | var maxCounter = 0; 23 | var i = data.length - 1; 24 | var result = []; 25 | var date; 26 | var nextDate; 27 | // fill the empty date 28 | var fillDate = function (endDate) { 29 | // 24 * 3600 * 1000 = 86400000 30 | date = new Date(86400000 + date.getTime()); 31 | while (date < endDate) { 32 | result.push({ 33 | date: date, 34 | counter: 0 35 | }); 36 | date = new Date(86400000 + date.getTime()); 37 | } 38 | }; 39 | for (; i >= 0; i--) { 40 | d = data[i]; 41 | maxCounter = Math.max(maxCounter, d.counter); 42 | date = util.strToDate(d.date); 43 | result.push({ 44 | date: date, 45 | counter: d.counter 46 | }); 47 | 48 | if (i === 0) { 49 | break; 50 | } 51 | nextDate = util.strToDate(data[i - 1].date); 52 | fillDate(nextDate); 53 | } 54 | var today = util.tomorrow(); 55 | fillDate(today); 56 | 57 | // generate event statistic map 58 | var html = ''; 59 | i = result.length - 1; 60 | var barWidth = 100 / (i + 1); 61 | for (; i >= 0; i--) { 62 | d = result[i]; 63 | html += util.format(eventsStatisModule.MOD_BAR_HTML, { 64 | date: d.date.toDateString(), 65 | counter: d.counter, 66 | /* safari has the sub-pixel issue*/ 67 | width: barWidth, 68 | height: (d.counter / maxCounter) * 100, 69 | visibility: d.counter ? 'visible' : 'hidden' 70 | }); 71 | } 72 | 73 | // rend all 74 | card.appendModHTML( 75 | 'eventsStatis', 76 | util.format(eventsStatisModule.MOD_HTML, { 77 | map: html 78 | }) 79 | ); 80 | callback(); 81 | }; 82 | 83 | eventsStatisModule.MOD_HTML = '' 84 | + '

    Events

    ' 85 | + '
    #{map}
    ' 86 | + '
    ' 87 | + '' 88 | + 'Now' 89 | + '' 90 | + '
    '; 91 | eventsStatisModule.MOD_BAR_HTML = '' 92 | + '
    ' 93 | + '
    ' 94 | + '#{date} - #{counter}' 95 | + '
    ' 96 | + '
    '; 97 | 98 | modules.add('eventsStatis', eventsStatisModule); 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/module/footer.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * private footer module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var footerModule = function (card, callback) { 10 | var noFooter = card.config.noFooter; 11 | if (noFooter && noFooter !== 'false') { 12 | callback(); 13 | return; 14 | } 15 | 16 | var link = document.createElement('a'); 17 | link.href = 'http://octocard.in/'; 18 | link.target = '_blank'; 19 | link.className = 'octocard-footer'; 20 | link.innerHTML = 'Octocard.in'; 21 | card.element.appendChild(link); 22 | callback(); 23 | }; 24 | 25 | modules.add('footer', footerModule); 26 | 27 | -------------------------------------------------------------------------------- /src/module/orgs.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * Orgs module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var orgsModule = function (card, callback) { 10 | var data = card.data.orgs; 11 | 12 | // if input user has no Organization, 13 | // don't show this module 14 | if (data.length === 0) { 15 | callback(); 16 | return; 17 | } 18 | 19 | var orgsNum = parseInt(card.config.orgsNum, 10) || -1; 20 | if (orgsNum >= 0) { 21 | data = data.slice(0, orgsNum); 22 | } 23 | 24 | var liHtml = ''; 25 | for (var i = 0, l = data.length; i < l; i++) { 26 | liHtml += util.format(orgsModule.MOD_LI_HTML, data[i]); 27 | } 28 | card.appendModHTML( 29 | 'orgs', 30 | util.format(orgsModule.MOD_HTML, liHtml) 31 | ); 32 | callback(); 33 | }; 34 | 35 | orgsModule.MOD_HTML = '' 36 | + '

    Organizations

    ' 37 | + '
      ' 38 | + '#{v}' 39 | + '
    '; 40 | orgsModule.MOD_LI_HTML = '' 41 | + '
  • ' 42 | + '' 43 | + '#{login}' 44 | + '' 45 | + '
  • '; 46 | 47 | modules.add('orgs', orgsModule); 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/module/repos.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * Repos module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var reposModule = function (card, callback) { 10 | var i; 11 | var l; 12 | data = card.data.repos; 13 | 14 | // if no repos, don't show this module 15 | if (data.length === 0) { 16 | callback(); 17 | return; 18 | } 19 | 20 | // sort data by stars 21 | data.sort(function (a, b) { 22 | return b.watchers_count - a.watchers_count; 23 | }); 24 | 25 | // calc ignore rule 26 | var reposIgnored = card.config.reposIgnored; 27 | var isIgnored = {}; 28 | if (reposIgnored) { 29 | reposIgnored = reposIgnored.split(','); 30 | for (i = 0, l = reposIgnored.length; i < l; i++) { 31 | isIgnored[reposIgnored[i]] = 1; 32 | } 33 | } 34 | 35 | // max reposNum 36 | var reposNum = parseInt(card.config.reposNum, 10) || 3; 37 | var usedRepoNum; 38 | var html = '
      '; 39 | for (i = 0, usedRepoNum = 0, l = data.length; i < l; i++) { 40 | if (usedRepoNum === reposNum) { 41 | break; 42 | } 43 | if (isIgnored[data[i].name]) { 44 | // ignore this repo 45 | continue; 46 | } 47 | 48 | // rend html 49 | usedRepoNum++; 50 | html += util.format(reposModule.MOD_LI_HTML, data[i]); 51 | } 52 | html += '
    '; 53 | card.appendModHTML('repos', html); 54 | callback(); 55 | }; 56 | 57 | reposModule.MOD_LI_HTML = '' 58 | + '
  • ' 59 | + '' 60 | + '

    #{name}

    ' 61 | + '

    #{description}

    ' 62 | + '#{watchers_count}✭' 63 | + '
    ' 64 | + '
  • '; 65 | 66 | modules.add('repos', reposModule); 67 | 68 | -------------------------------------------------------------------------------- /src/module/stats.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | /** 4 | * Stats module. 5 | * 6 | * @param {Octocard} card . 7 | * @param {Function} callback . 8 | */ 9 | var statsModule = function (card, callback) { 10 | var html = util.format(statsModule.MOD_HTML, card.data.base); 11 | card.appendModHTML('stats', html); 12 | callback(); 13 | }; 14 | 15 | statsModule.MOD_HTML = '' 16 | + ''; 42 | 43 | modules.add('stats', statsModule); 44 | -------------------------------------------------------------------------------- /src/modules.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true */ 2 | 3 | var modules = { 4 | mods: {}, 5 | /** 6 | * Get module. 7 | * 8 | * @param {string} name module name. 9 | */ 10 | get: function(name) { 11 | return this.mods[name]; 12 | }, 13 | /** 14 | * Add module. 15 | * 16 | * @param {string} name . 17 | * @param {Function} module . 18 | */ 19 | add: function(name, module) { 20 | this.mods[name] = module; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true, eqnull:true */ 2 | 3 | var dateReg = /(\d{4})-(\d{2})-(\d{2})T/; 4 | var util = { 5 | /** 6 | * Insert css text. 7 | * 8 | * @param {string} css css style text. 9 | * @return {Element} style element. 10 | */ 11 | createStyle: function (css) { 12 | var style = document.createElement('style'); 13 | style.type = 'text/css'; 14 | 15 | if (style.styleSheet) { 16 | // IE 17 | style.styleSheet.cssText = css; 18 | } else { 19 | style.appendChild(document.createTextNode(css)); 20 | } 21 | return style; 22 | }, 23 | 24 | /** 25 | * format 26 | * util.format('hello #{v}', 'world'); 27 | * util.format('hello #{a}, I like #{b}', {a: 'world', b: 'book'}); 28 | * 29 | * @param {string} tmpl template text. 30 | * @param {string|Object} _key key or object. 31 | * @param {string} _value value. 32 | */ 33 | format: function (tmpl, _key, _val) { 34 | if (!_key) { 35 | return tmpl; 36 | } 37 | var val; 38 | 39 | if (typeof _key !== 'object') { 40 | var key = _val ? _key : '#{v}'; 41 | val = _val || _key; 42 | return tmpl.replace(new RegExp(key, 'g'), ('' + val)); 43 | } else { 44 | var obj = _key; 45 | return tmpl.replace(_val || /#\{([^{}]+)\}/g, function(match, key) { 46 | val = obj[key]; 47 | return (val == null) ? '' : ('' + val); 48 | }); 49 | } 50 | }, 51 | 52 | // cacheKey: 'githubcard-data', 53 | /** 54 | * Get JSONP call result cache. 55 | * 56 | * @param {string} url . 57 | * @return {Object} data. 58 | getJSONPCache: function (url) { 59 | var value = localStorage.getItem(util.cacheKey); 60 | if (value) { 61 | value = JSON.parse(value); 62 | value = value[url.replace( 63 | /([?&])callback=[^$&]+(&?)/, 64 | function (str, $1) { 65 | return $1; 66 | } 67 | )]; 68 | } 69 | 70 | // not found 71 | if (!value) { 72 | return null; 73 | } 74 | 75 | // out of time 76 | var now = new Date(); 77 | if (value.last <= now) { 78 | localStorage.removeItem(util.cacheKey); 79 | return null; 80 | } 81 | 82 | return value.data; 83 | }, 84 | */ 85 | 86 | /** 87 | * Set JSONP cache. 88 | * 89 | * @param {string} url url string. 90 | * @param {Object} data . 91 | * @param {number} hour cache last `n` hour. 92 | setJSONPCache: function (url, data, hour) { 93 | var value = localStorage.getItem(util.cacheKey); 94 | if (value) { 95 | value = JSON.parse(value); 96 | } else { 97 | value = {}; 98 | } 99 | 100 | url = url.replace( 101 | /([?&])callback=[^$&]+(&?)/, 102 | function (str, $1) { 103 | return $1; 104 | } 105 | ); 106 | value[url] = { 107 | last: util.getTime((-1 * hour) / 24).toString(), 108 | data: data 109 | }; 110 | 111 | localStorage.setItem(util.cacheKey, JSON.stringify(value)); 112 | }, 113 | */ 114 | 115 | /** 116 | * jsonp 117 | * 118 | * @param {string} url . 119 | * @param {Function} success success callback. 120 | * @param {Function=} fail failed callback. 121 | */ 122 | jsonp: function (url, success, fail) { 123 | /* 124 | // find cache 125 | var cache = util.getJSONPCache(url); 126 | if (cache) { 127 | success(cache); 128 | return; 129 | } 130 | */ 131 | 132 | // no cache 133 | var script = document.createElement('script'); 134 | var callbackName = 'githubcardjsonp' + (new Date().getTime()); 135 | var timer; 136 | var timeout = 50000; 137 | var scriptLoaded = 0; 138 | var successed = false; 139 | 140 | // create script 141 | var re = url.match(/[?&]callback=([^$&]+)/); 142 | if (re) { 143 | // callback exist 144 | script.src = url.replace(/([?&]callback=)[^$&]+/, '$1' + callbackName); 145 | } else { 146 | // append url 147 | script.src = url 148 | + (url.indexOf('?') === -1 ? '?' : '&') 149 | + 'callback=' + callbackName; 150 | } 151 | script.type = 'text/javascript'; 152 | script.charset = 'UTF-8'; 153 | 154 | // jsonp callback 155 | window[callbackName] = function (data) { 156 | if (!data.success) { 157 | fail(data.message); 158 | successed = true; 159 | return; 160 | } 161 | successed = true; 162 | // util.setJSONPCache(url, data, 0.5); 163 | success(data.data); 164 | window[callbackName] = null; 165 | }; 166 | 167 | // call fail function and clear script 168 | var callFail = function () { 169 | if (!successed && fail) { 170 | fail('Server or network error.'); 171 | } 172 | script.onload = script.onreadystatechange = null; 173 | document.body.removeChild(script); 174 | }; 175 | 176 | // IE/opera support onreadystatechange 177 | // safari/chrome/opera support onload 178 | script.onload = script.onreadystatechange = function () { 179 | // for opera 180 | if (scriptLoaded) { 181 | return; 182 | } 183 | 184 | var readyState = script.readyState; 185 | if ('undefined' == typeof readyState || 186 | readyState == 'loaded' || 187 | readyState == 'complete') { 188 | 189 | scriptLoaded = 1; 190 | callFail(); 191 | clearTimeout(timer); 192 | } 193 | }; 194 | 195 | // timer 196 | timer = setTimeout(function () { 197 | callFail(); 198 | // make it not report error 199 | // when callback fire too late 200 | window[callbackName] = function () {}; 201 | }, timeout); 202 | 203 | document.body.appendChild(script); 204 | }, 205 | 206 | /** 207 | * bind event 208 | * 209 | * @param {Element} element . 210 | * @param {string} event . 211 | * @param {Function} callback . 212 | */ 213 | bind: function (element, event, callback) { 214 | if (element.addEventListener) { 215 | element.addEventListener(event, callback, false); 216 | } else { 217 | element.attachEvent('on' + event, callback); 218 | } 219 | }, 220 | 221 | /** 222 | * reset time part of a date. 223 | * 224 | * @param {Date} date . 225 | * @return {Date} date. 226 | */ 227 | resetTime: function (date) { 228 | date.setMilliseconds(0); 229 | date.setMinutes(0); 230 | date.setHours(0); 231 | date.setSeconds(0); 232 | return date; 233 | }, 234 | 235 | /** 236 | * test same day. 237 | * 238 | * @param {Date} d1 date one. 239 | * @param {Date} d2 date two. 240 | * @return {boolean} is the same day. 241 | isSameDay: function (d1, d2) { 242 | return d1.toDateString() === d2.toDateString(); 243 | }, 244 | */ 245 | 246 | /** 247 | * Get today, time is '00:00:00' 248 | * 249 | * @return {Date} today. 250 | */ 251 | today: function () { 252 | return util.resetTime(new Date()); 253 | }, 254 | 255 | /** 256 | * next day, time is '00:00:00' 257 | * 258 | * @return {Date} next day. 259 | */ 260 | nextDay: function (cur) { 261 | return new Date(cur.getTime() + 86400000); 262 | }, 263 | 264 | /** 265 | * tomorrow, time is '00:00:00' 266 | * 267 | * @return {Date} tomorrow. 268 | */ 269 | tomorrow: function () { 270 | return util.nextDay(util.today()); 271 | }, 272 | 273 | /** 274 | * time string to date 275 | * 276 | * @param {string} str time string. 277 | * @return {Date} date . 278 | */ 279 | strToDate: function (str) { 280 | var r = str.match(dateReg); 281 | return new Date(r[1], r[2] - 1, r[3], 0, 0, 0, 0); 282 | }, 283 | 284 | /** 285 | * Get document page height 286 | * 287 | * @param {Document} doc document. 288 | * @return {number} height 289 | */ 290 | getPageHeight: function (doc) { 291 | var scrollProp = 'scrollHeight'; 292 | var offsetProp = 'offsetHeight'; 293 | var element = doc.documentElement; 294 | var body = doc.body; 295 | return Math.max( 296 | body[scrollProp], 297 | body[offsetProp], 298 | element[scrollProp], 299 | element[offsetProp] 300 | ); 301 | }, 302 | 303 | /** 304 | * get ShadowRoot, if not existed then create it. 305 | * 306 | * @param {Element} div . 307 | * @return {Element} shadow root. 308 | */ 309 | getShadowRoot: function (div) { 310 | var prefixs = ['', 'webkit', 'moz', 'ms']; 311 | var root; 312 | for (var i = 0, l = prefixs.length; i < l; i++) { 313 | root = this._getShadowRoot(div, prefixs[i]); 314 | if (root) { 315 | return root; 316 | } 317 | } 318 | }, 319 | _getShadowRoot: function (div, prefix) { 320 | var methodName = 'createShadowRoot'; 321 | var rootName = 'shadowRoot'; 322 | 323 | if (prefix) { 324 | methodName = prefix + util.capitalize(methodName); 325 | rootName = prefix + util.capitalize(rootName); 326 | } 327 | 328 | if (typeof div[methodName] === 'function') { 329 | var root = div[rootName]; 330 | if (root) { 331 | root.innerHTML = ''; 332 | return root; 333 | } 334 | root = div[methodName](); 335 | root.resetStyleInheritance = true; 336 | return root; 337 | } 338 | }, 339 | 340 | /** 341 | * capitalize first letter. 342 | * 343 | * @param {string} str input. 344 | * @return {string} result. 345 | */ 346 | capitalize: function (str) { 347 | return str.charAt(0).toUpperCase() + str.slice(1); 348 | }, 349 | 350 | /** 351 | * Get size class by width. 352 | * 353 | * @param {Element} hos host element. 354 | * @param {Element} root root element maybe shadow dom. 355 | */ 356 | addSizeClass: function (host, root) { 357 | var width = host.offsetWidth; 358 | var rules = [0, 240, 480]; 359 | var classMap = { 360 | '480': 'octocard-max', 361 | '240': 'octocard-mid', 362 | '0': 'octocard-min' 363 | }; 364 | 365 | var nextRule; 366 | var rule; 367 | for (var i = 0; i < rules.length; i++) { 368 | rule = rules[i]; 369 | nextRule = rules[i + 1]; 370 | if (width >= rule && ((width < nextRule) || !nextRule)) { 371 | break; 372 | } 373 | } 374 | 375 | if (root.getAttribute('data-rule') == rule) { 376 | return; 377 | } 378 | 379 | root.className = 380 | root.className.replace(/(^| )octocard\-m[^ $]+/, '') 381 | + ' ' + classMap[rule]; 382 | root.setAttribute('data-rule', rule); 383 | } 384 | }; 385 | -------------------------------------------------------------------------------- /theme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Theme builder 6 | 7 | 25 | 26 | 27 |
    28 |
    29 |
    30 | 31 | 32 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /themes/azzura-black.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed by cresstoo. 3 | * https://github.com/cresstoo/github-card-theme 4 | */ 5 | @import "azzura.less"; 6 | 7 | /* configs */ 8 | @mainPrimaryColor: #3C3C3C; 9 | @mainLightenPrimaryColor: lighten(#3C3C3C, 20%); 10 | -------------------------------------------------------------------------------- /themes/azzura.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Designed by cresstoo. 3 | * https://github.com/cresstoo/github-card-theme 4 | */ 5 | @import "base.less"; 6 | 7 | /* configs */ 8 | @mainPrimaryColor: #4A90E2; 9 | @mainLightenPrimaryColor: #8FBAEC; 10 | @mainErrorColor: #DA4453; 11 | 12 | /* configs for base element */ 13 | @mainFontColor: #888; 14 | @mainLightenFontColor: #888; 15 | @mainLightestFontColor: #CCC; 16 | @mainDarkenFontColor: @mainFontColor; 17 | 18 | @mainBorderColor: #EFEFEF; 19 | @mainLightenBorderColor: transparent; 20 | @mainBackgroundColor: #FFF; 21 | @mainDarkenBackgroundColor: @mainPrimaryColor; 22 | 23 | /* configs for base module */ 24 | @baseTitleColor: #FFF; 25 | 26 | /* configs for details module */ 27 | @detailsPrefixColor: @mainFontColor; 28 | 29 | /* configs for stats module */ 30 | @statsNumberColor: @mainPrimaryColor; 31 | 32 | /* configs for footer module */ 33 | @footerBackgroundColor: transparent; 34 | @footerBorderColor: @mainBorderColor; 35 | 36 | /* resert css */ 37 | #root-id { 38 | margin: 0 2px 2px 0; 39 | -webkit-box-shadow: 1px 1px 1px #CCC; 40 | box-shadow: 1px 1px 1px #CCC; 41 | } 42 | #root-id .octocard-m h2 { 43 | font-weight: normal; 44 | } 45 | #root-id .octocard-m { 46 | padding-left: 1em; 47 | padding-right: 1em; 48 | padding-top: 10px; 49 | margin-left: -1em; 50 | margin-right: -1em; 51 | margin-bottom: 0; 52 | } 53 | #root-id.octocard-min .octocard-m { 54 | padding-top: 5px; 55 | padding-bottom: 5px; 56 | } 57 | 58 | /* module/base css */ 59 | #root-id .octocard-m-base { 60 | } 61 | #root-id .octocard-m-base a { 62 | padding: 1em 0; 63 | } 64 | #root-id .octocard-m-base a::after { 65 | content: 'FOLLOW'; 66 | position: absolute; 67 | top: -14px; 68 | right: -44px; 69 | color: #FFF; 70 | background-color: #F5A623; 71 | width: 100px; 72 | text-align: center; 73 | font-size: 12px; 74 | border: 1px solid #666; 75 | box-sizing: border-box; 76 | -webkit-transform: rotate(45deg); 77 | transform: rotate(45deg); 78 | -webkit-transform-origin: top left; 79 | transform-origin: top left; 80 | } 81 | #root-id.octocard-min .octocard-m-base a::after { 82 | top: -10px; 83 | right: -57px; 84 | -webkit-transform: rotate(45deg) scale(.75, .75); 85 | transform: rotate(45deg) scale(.75, .75); 86 | } 87 | #root-id .octocard-m-base img { 88 | border-radius: 100%; 89 | background: @mainBackgroundColor; 90 | } 91 | #root-id .octocard-m-base a:hover h1 { 92 | color: @baseTitleColor; 93 | } 94 | 95 | #root-id .octocard-m-base a span, 96 | #root-id .octocard-m-base a:hover span { 97 | color: #EAEAEA; 98 | color: rgba(255, 255, 255, 0.6); 99 | } 100 | 101 | /* module/details css */ 102 | #root-id .octocard-m-details { 103 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAA8CAYAAABxVAqfAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzhGMzMyOUE2RTQ0MTFFNDg2MkI4QUM3QjI1NjRBRDMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzhGMzMyOUI2RTQ0MTFFNDg2MkI4QUM3QjI1NjRBRDMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEMjE5NzVFMTZFM0ExMUU0ODYyQjhBQzdCMjU2NEFEMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEMjE5NzVFMjZFM0ExMUU0ODYyQjhBQzdCMjU2NEFEMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrQtusQAAAMXSURBVHjaxJk7aFRBFIZ3dXFRUUPwUdr5CgExJBpBULBTC4sVZMFHISh2gXQ2FkpwG0tB1ASUiCnTaOUDIaIRItH4QNGIjWLci4/V3UXIP/gPXC93Zue1uQM/ubu5k2/OmTMzZ07yjUYj1+a2FNqf/LJQq9VCg4pQH1SG1kOd/Pw/OCCwGxqAevisbYUA1h2GjkL9/GzUCp4WnoMOuHQuOFp5iZYWXUe9yPJ9Yd0T6JgP1NZiAR3zBdpaHBRqCg4ONQG3BdoK3DaoDryxnVAVeBlUMYDOQHugYWg6BPiQ4W40BN2DjkO9HMS46zoW1g4a9v0Qe65zEBPc0QYSB4XwyFy8cz6Kovjna9yVWrUpWhhpttWr0H3oDQdUV1m8hW42aXMaqPRA2XSO++jqBWkSvMpibnM87LeGAHfR1aatA1obAly27CcStS++4DXQTst+txjZXuC9lvMldqzTIYLrp2WfCl3tDR6yeH+Kbg6ynGyi+UcIa12SvXcLmfrE2+WswEuyAjeyAp/ICrwhK/DvrMA9lus+GLgj7XbvCj5r2WcwRKYiwM8s+9jkZlpwFfrmYHXRFyzy4UkHq72uODK4bjj0lZe6bh/wY8fjzrk0IcGvoFFN8n5bk2MVeQORA9htMoj4FWYX9CDlnafQQSaFD6Hv0LoWf1felUagz/So8u4kNodHvBsn26/cvyJaE7oOrbDw6l2olATHd66IyyRtrpfzEibeP0K4af59KglN2zLHNcncSugM9JyunzUAi7h5bbpXV5JXysQhIbyyjfl1qzZic0jMcE5Uy0sE4VvoI8sQF/n9J/6c4LRN60oUqtNJ5/LN0BXoJMsQq+mh8/z9ZMwbkclySivC3FTUQ2q8xowy0jdB76HtzL3/cjAvXcBycxjTFGOEZy5wfaeVrEQ0f3UBm8BTiyuMhX3QHZOqj6qeUWoBVx0Uf3xTHwkf1iy1VI+GyLnqjOKSJTxIsicDqtfBem+wDCZpva6OuVg5B9Vq1ddrIur7eXrF/0Ei9ugdqk0k32w2cwGbKFt18lkkkC9UL84LMAD+2rou4OZaogAAAABJRU5ErkJggg==') right center no-repeat; 104 | } 105 | 106 | /* module/repos css */ 107 | #root-id .octocard-m-repos h2 { 108 | font-weight: normal; 109 | color: @mainPrimaryColor; 110 | } 111 | #root-id.octocard-min .octocard-m-repos span { 112 | float: right; 113 | } 114 | #root-id.octocard-min .octocard-m-repos a { 115 | margin-top: 0.25em; 116 | margin-bottom: 0.25em; 117 | } 118 | 119 | /* module/orgs css */ 120 | #root-id .octocard-m-orgs img { 121 | width: 34px; 122 | height: 34px; 123 | padding: 0; 124 | border-color: #888; 125 | border-radius: 100%; 126 | } 127 | 128 | /* module/stats css */ 129 | #root-id .octocard-m-stats { 130 | padding-top: 0; 131 | padding-bottom: 0; 132 | } 133 | #root-id .octocard-m-stats ul { 134 | height: 42px + 10px * 2; 135 | } 136 | #root-id .octocard-m-stats li { 137 | padding-top: 10px; 138 | padding-bottom: 10px; 139 | margin-left: -1px; 140 | border-left: 1px solid @mainBorderColor; 141 | -webkit-box-sizing: border-box; 142 | box-sizing: border-box; 143 | } 144 | #root-id .octocard-m-stats a strong { 145 | font-weight: normal; 146 | font-size: 20px; 147 | line-height: 33px; 148 | } 149 | 150 | #root-id.octocard-min .octocard-m-stats { 151 | padding-top: 0; 152 | padding-bottom: 0; 153 | } 154 | #root-id.octocard-min .octocard-m-stats a strong { 155 | font-size: 18px; 156 | line-height: 28px; 157 | } 158 | #root-id.octocard-min .octocard-m-stats ul { 159 | height: 37px + 10px * 2; 160 | } 161 | 162 | /* module/eventsstatis css */ 163 | #root-id .octocard-m-eventsstatis-bd { 164 | height: 60px; 165 | } 166 | #root-id .octocard-m-eventsstatis-bar div { 167 | width: 75%; 168 | } 169 | #root-id .octocard-m-eventsstatis-date { 170 | display: none; 171 | } 172 | #root-id.octocard-min .octocard-m-eventsstatis-bd { 173 | height: 36px; 174 | } 175 | -------------------------------------------------------------------------------- /themes/base.less: -------------------------------------------------------------------------------- 1 | /* configs */ 2 | @mainPrimaryColor: #4A89DC; 3 | @mainLightenPrimaryColor: #5D9CEC; 4 | @mainErrorColor: #DA4453; 5 | 6 | /* configs for base element */ 7 | @mainFontColor: #666; 8 | @mainLightenFontColor: #999; 9 | @mainLightestFontColor: #EAEAEA; 10 | @mainDarkenFontColor: #333; 11 | @mainBorderColor: #CCC; 12 | @mainLightenBorderColor: #DDD; 13 | @mainBackgroundColor: #FFF; 14 | @mainDarkenBackgroundColor: #EFEFEF; 15 | @mainLinkColor: @mainFontColor; 16 | @mainHoverLinkColor: @mainPrimaryColor; 17 | @mainFontFamily: "Helvetica Neue", Arial, Helvetica, sans-serif; 18 | 19 | /* configs for all modules' base element */ 20 | @mainModuleTitleColor: @mainDarkenFontColor; 21 | @mainModuleBorderColor: @mainBorderColor; 22 | 23 | /* configs for error module */ 24 | @errorFontColor: @mainErrorColor; 25 | 26 | /* configs for loading module */ 27 | @loadingCubeColor: @mainLightenPrimaryColor; 28 | @loadingCubeHighlightColor: @mainPrimaryColor; 29 | @loadingBackgroundColor: rgba(255, 255, 255, 0.8); 30 | 31 | /* configs for base module */ 32 | @baseTitleColor: @mainModuleTitleColor; 33 | @baseBackgroundColor: @mainDarkenBackgroundColor; 34 | @baseImgBorderColor: @mainLightenBorderColor; 35 | @baseImgHoverBorderColor: @mainHoverLinkColor; 36 | @baseHoverTitleColor: @mainHoverLinkColor; 37 | 38 | /* configs for details module */ 39 | @detailsPrefix: "-"; 40 | @detailsPrefixColor: @mainLightestFontColor; 41 | 42 | /* configs for orgs module */ 43 | @orgsBorderColor: @mainLightenBorderColor; 44 | @orgsHoverBorderColor: @mainHoverLinkColor; 45 | 46 | /* configs for repos module */ 47 | @reposHoverTitleColor: @mainHoverLinkColor; 48 | @reposStarColor: @mainLightenFontColor; 49 | 50 | /* configs for stats module */ 51 | @statsNumberColor: @mainDarkenFontColor; 52 | @statsHoverNumberColor: @mainHoverLinkColor; 53 | @statsTextColor: @mainLightenFontColor; 54 | @statsHoverTextColor: @mainHoverLinkColor; 55 | 56 | /* configs for eventsstatis module */ 57 | @eventsstatisBarColor: @mainLightenPrimaryColor; 58 | @eventsstatisDateColor: @mainLightenFontColor; 59 | 60 | /* configs for footer module */ 61 | @footerBackgroundColor: @mainDarkenBackgroundColor; 62 | @footerBorderColor: @mainBorderColor; 63 | 64 | /* resert css */ 65 | #root-id { 66 | position: relative; 67 | padding: 1em; 68 | min-height: 40px; 69 | display: block; 70 | color: @mainFontColor; 71 | font: 14px @mainFontFamily; 72 | text-align: left; 73 | line-height: 1.5; 74 | border: 1px solid @mainBorderColor; 75 | background-color: @mainBackgroundColor; 76 | -webkit-box-sizing: border-box; 77 | -moz-box-sizing: border-box; 78 | box-sizing: border-box; 79 | } 80 | #root-id.octocard-min { 81 | font-size: 12px; 82 | } 83 | #root-id span, 84 | #root-id img, 85 | #root-id ul, 86 | #root-id ol, 87 | #root-id h1, 88 | #root-id h2, 89 | #root-id li, 90 | #root-id p, 91 | #root-id div { 92 | margin: 0; 93 | padding: 0; 94 | border: none; 95 | float: none; 96 | position: static; 97 | overflow: hidden; 98 | width: auto; 99 | height: auto; 100 | line-height: inherit; 101 | color: inherit; 102 | font-size: inherit; 103 | font-weight: normal; 104 | background: none; 105 | } 106 | #root-id h1, 107 | #root-id h2 { 108 | font-weight: bold; 109 | } 110 | #root-id li { 111 | list-style: none; 112 | } 113 | #root-id p, 114 | #root-id div, 115 | #root-id img { 116 | display: block; 117 | } 118 | #root-id a, 119 | #root-id span { 120 | display: inline; 121 | font-size: inherit; 122 | text-decoration: none; 123 | } 124 | #root-id a { 125 | color: @mainLinkColor; 126 | text-decoration: none; 127 | -webkit-transition: color 0.5s ease; 128 | transition: color 0.5s ease; 129 | } 130 | #root-id a:hover { 131 | color: @mainHoverLinkColor; 132 | text-decoration: none; 133 | } 134 | #root-id .octocard-m { 135 | position: relative; 136 | width: 100%; 137 | padding: 0 0 10px 0; 138 | margin: 0 0 10px 0; 139 | border-bottom: 1px solid @mainModuleBorderColor; 140 | } 141 | #root-id .octocard-m:last-child { 142 | margin-bottom: 0; 143 | padding-bottom: 0; 144 | border-bottom: none; 145 | } 146 | #root-id .octocard-m h2 { 147 | color: @mainModuleTitleColor; 148 | } 149 | #root-id .octocard-error { 150 | display: inline-block; 151 | vertical-align: middle; 152 | color: @errorFontColor; 153 | } 154 | #root-id .octocard-error a { 155 | margin-left: 10px; 156 | } 157 | 158 | /* loader css */ 159 | #root-id .octocard-loading { 160 | position: absolute; 161 | top: 0; 162 | left: 0; 163 | height: 100%; 164 | width: 100%; 165 | background-color: @loadingBackgroundColor; 166 | } 167 | #root-id .octocard-loading-inner { 168 | position: absolute; 169 | top: 50%; 170 | left: 50%; 171 | width: 80px; 172 | height: 20px; 173 | margin-left: -40px; 174 | margin-top: -10px; 175 | overflow: visible; 176 | } 177 | #root-id .octocard-loading-0, 178 | #root-id .octocard-loading-1, 179 | #root-id .octocard-loading-2 { 180 | float: left; 181 | width: 20px; 182 | height: 100%; 183 | margin-right: 10px; 184 | background: @loadingCubeColor; 185 | } 186 | #root-id .octocard-loading-2 { 187 | margin-right: 0; 188 | } 189 | #root-id .octocard-loading-cur { 190 | background-color: @loadingCubeHighlightColor; 191 | -webkit-transform: scale(1.2); 192 | -ms-transform: scale(1.2); 193 | transform: scale(1.2); 194 | } 195 | 196 | /* module/base css */ 197 | #root-id .octocard-m-base { 198 | margin: -1em -1em 10px -1em; 199 | padding: 0.5em 1em; 200 | background-color: @baseBackgroundColor; 201 | } 202 | #root-id .octocard-m-base a { 203 | display: block; 204 | } 205 | #root-id .octocard-m-base a:hover { 206 | text-decoration: none; 207 | } 208 | #root-id .octocard-m-base h1 { 209 | color: @baseTitleColor; 210 | } 211 | #root-id .octocard-m-base img { 212 | float: left; 213 | margin-right: 10px; 214 | padding: 1px; 215 | width: 44px; 216 | height: 44px; 217 | border: 1px solid @baseImgBorderColor; 218 | -webkit-transition: border-color 0.5s ease; 219 | transition: border-color 0.5s ease; 220 | } 221 | #root-id .octocard-m-base a:hover img { 222 | border-color: @baseImgHoverBorderColor; 223 | } 224 | #root-id .octocard-m-base span, 225 | #root-id .octocard-m-base h1 { 226 | overflow: hidden; 227 | line-height: 28px; 228 | font-size: 20px; 229 | white-space: nowrap; 230 | text-overflow: ellipsis; 231 | -webkit-transition: color 0.5s ease; 232 | transition: color 0.5s ease; 233 | } 234 | #root-id .octocard-m-base a:hover h1 { 235 | color: @baseHoverTitleColor; 236 | } 237 | #root-id .octocard-m-base .octocard-m-base-noname { 238 | line-height: 48px; 239 | font-size: 24px; 240 | } 241 | #root-id .octocard-m-base span { 242 | display: block; 243 | font-size: 16px; 244 | line-height: 20px; 245 | } 246 | /* min base */ 247 | #root-id.octocard-min .octocard-m-base img { 248 | width: 36px; 249 | height: 36px; 250 | padding: 0; 251 | border: none; 252 | -webkit-box-shadow: none; 253 | box-shadow: none; 254 | } 255 | #root-id.octocard-min .octocard-m-base h1 { 256 | font-size: 16px; 257 | line-height: 20px; 258 | } 259 | #root-id.octocard-min .octocard-m-base .octocard-m-base-noname { 260 | font-size: 16px; 261 | line-height: 36px; 262 | } 263 | #root-id.octocard-min .octocard-m-base span { 264 | font-size: 14px; 265 | line-height: 16px; 266 | } 267 | 268 | /* module/details css */ 269 | #root-id .octocard-m-details li { 270 | white-space: nowrap; 271 | text-overflow: ellipsis; 272 | } 273 | #root-id .octocard-m-details li:before { 274 | content: @detailsPrefix; 275 | float: left; 276 | margin-right: 10px; 277 | color: @detailsPrefixColor; 278 | } 279 | #root-id .octocard-m-details a { 280 | display: block; 281 | overflow: hidden; 282 | text-overflow: ellipsis; 283 | } 284 | /* min details */ 285 | #root-id.octocard-min .octocard-m-details li:before { 286 | display: none; 287 | } 288 | /* max details */ 289 | #root-id.octocard-max .octocard-m-details li { 290 | float: left; 291 | margin-right: 2%; 292 | width: 48%; 293 | } 294 | 295 | 296 | /* module/orgs css */ 297 | #root-id .octocard-m-orgs h2 { 298 | margin-bottom: 5px; 299 | } 300 | #root-id .octocard-m-orgs ul { 301 | margin: 0; 302 | padding: 0; 303 | overflow: hidden; 304 | list-style: none; 305 | } 306 | #root-id .octocard-m-orgs li { 307 | list-style: none; 308 | float: left; 309 | margin-right: 4px; 310 | margin-bottom: 4px; 311 | } 312 | #root-id .octocard-m-orgs li:last-child { 313 | margin-right: 0; 314 | } 315 | #root-id .octocard-m-orgs a { 316 | float: left; 317 | text-decoration: none; 318 | color: inherit; 319 | } 320 | #root-id .octocard-m-orgs img { 321 | padding: 1px; 322 | width: 32px; 323 | height: 32px; 324 | border: 1px solid @orgsBorderColor; 325 | } 326 | #root-id .octocard-m-orgs a:hover img { 327 | border-color: @orgsHoverBorderColor; 328 | } 329 | /* min orgs */ 330 | #root-id.octocard-min .octocard-m-orgs img { 331 | padding: 0; 332 | width: 24px; 333 | height: 24px; 334 | border: none; 335 | } 336 | 337 | /* module/repos css */ 338 | #root-id .octocard-m-repos ul { 339 | margin: 0; 340 | padding: 0; 341 | overflow: hidden; 342 | list-style: none; 343 | } 344 | #root-id .octocard-m-repos li { 345 | list-style: none; 346 | } 347 | #root-id .octocard-m-repos a { 348 | position: relative; 349 | display: block; 350 | text-decoration: none; 351 | color: inherit; 352 | } 353 | #root-id .octocard-m-repos a { 354 | width: 100%; 355 | } 356 | #root-id .octocard-m-repos a h2, 357 | #root-id .octocard-m-repos a p { 358 | font-size: 14px; 359 | margin-right: 50px; 360 | white-space: nowrap; 361 | text-overflow: ellipsis; 362 | } 363 | #root-id .octocard-m-repos a:hover h2 { 364 | color: @reposHoverTitleColor; 365 | -webkit-transition: color 0.5s ease; 366 | transition: color 0.5s ease; 367 | } 368 | #root-id .octocard-m-repos a span { 369 | position: absolute; 370 | top: 50%; 371 | right: 0; 372 | margin-top: -10.5px; 373 | line-height: 1.5; 374 | font-size: 14px; 375 | color: @reposStarColor; 376 | } 377 | /* min repos */ 378 | #root-id.octocard-min .octocard-m-repos a { 379 | margin: 0.15em 0; /* (1.5 - 1.2) / 2 = 0.15 */ 380 | line-height: 1.2; 381 | } 382 | #root-id.octocard-min .octocard-m-repos p { 383 | display: none; 384 | } 385 | #root-id.octocard-min .octocard-m-repos h2 { 386 | margin-right: 0.25em; 387 | display: inline; 388 | white-space: initial; 389 | word-wrap: break-word; 390 | } 391 | #root-id.octocard-min .octocard-m-repos span { 392 | display: inline; 393 | position: static; 394 | margin: 0; 395 | font-size: 12px; 396 | } 397 | /* max repos */ 398 | #root-id.octocard-max .octocard-m-repos h2 { 399 | font-size: 16px; 400 | } 401 | #root-id.octocard-max .octocard-m-repos p { 402 | white-space: initial; 403 | } 404 | 405 | 406 | /* module/stats css */ 407 | #root-id .octocard-m-stats ul { 408 | margin: 0; 409 | padding: 0; 410 | height: 42px; 411 | overflow: hidden; 412 | list-style: none; 413 | } 414 | #root-id .octocard-m-stats li, 415 | #root-id .octocard-m-stats a { 416 | float: left; 417 | width: 33.33%; 418 | text-decoration: none; 419 | list-style: none; 420 | color: inherit; 421 | text-align: center; 422 | } 423 | #root-id .octocard-m-stats a { 424 | width: 100%; 425 | } 426 | #root-id .octocard-m-stats a strong, 427 | #root-id .octocard-m-stats a span { 428 | display: block; 429 | width: 100%; 430 | line-height: 1.2; 431 | text-align: center; 432 | } 433 | #root-id .octocard-m-stats a:hover strong, 434 | #root-id .octocard-m-stats a:hover span { 435 | -webkit-transition: color 0.5s ease; 436 | transition: color 0.5s ease; 437 | } 438 | #root-id .octocard-m-stats a span { 439 | margin-top: -5px; 440 | font-size: 12px; 441 | color: @statsTextColor; 442 | } 443 | #root-id .octocard-m-stats a:hover span { 444 | color: @statsHoverTextColor; 445 | } 446 | #root-id .octocard-m-stats a strong { 447 | font-size: 28px; 448 | font-weight: bold; 449 | color: @statsNumberColor; 450 | } 451 | #root-id .octocard-m-stats a:hover strong { 452 | color: @statsHoverNumberColor; 453 | } 454 | /* min stats */ 455 | #root-id.octocard-min .octocard-m-stats ul { 456 | height: 37px; 457 | } 458 | #root-id.octocard-min .octocard-m-stats a strong { 459 | font-size: 24px; 460 | } 461 | #root-id.octocard-min .octocard-m-stats li { 462 | width: 50%; 463 | } 464 | /* max stats */ 465 | #root-id.octocard-max .octocard-m-stats li { 466 | width: 25%; 467 | } 468 | 469 | 470 | /* module/eventsStatis css */ 471 | #root-id .octocard-m-eventsstatis { 472 | position: relative; 473 | } 474 | #root-id .octocard-m-eventsstatis h2 { 475 | margin-bottom: 5px; 476 | } 477 | #root-id .octocard-m-eventsstatis-bd { 478 | overflow: hidden; 479 | width: 100%; 480 | height: 80px; 481 | } 482 | #root-id .octocard-m-eventsstatis-bar { 483 | position: relative; 484 | float: right; 485 | min-width: 3px; 486 | height: 100%; 487 | } 488 | #root-id .octocard-m-eventsstatis-bar div { 489 | position: absolute; 490 | bottom: 0; 491 | left: 0; 492 | width: 100%; 493 | text-indent: -9999px; 494 | background-color: @eventsstatisBarColor; 495 | } 496 | #root-id .octocard-m-eventsstatis-date { 497 | overflow: hidden; 498 | font-size: 12px; 499 | color: @eventsstatisDateColor; 500 | } 501 | #root-id .octocard-m-eventsstatis-date-end { 502 | float: right; 503 | } 504 | /* min eventsstatis */ 505 | #octocard.octocard-min .octocard-m-eventsstatis-bd { 506 | height: 48px; 507 | } 508 | #octocard.octocard-min .octocard-m-eventsstatis-date { 509 | display: none; 510 | } 511 | 512 | 513 | /* module/footer css */ 514 | #root-id:hover .octocard-footer { 515 | display: block; 516 | } 517 | #root-id .octocard-footer { 518 | position: absolute; 519 | bottom: -1px; 520 | right: -1px; 521 | display: none; 522 | padding: 1px 4px; 523 | z-index: 1; 524 | height: 12px; 525 | text-align: center; 526 | font-size: 12px; 527 | line-height: 12px; 528 | background-color: @footerBackgroundColor; 529 | border: 1px solid @footerBorderColor; 530 | } 531 | 532 | -------------------------------------------------------------------------------- /themes/clean.less: -------------------------------------------------------------------------------- 1 | @import "base.less"; 2 | 3 | /* configs */ 4 | @mainPrimaryColor: #4A89DC; 5 | @mainLightenPrimaryColor: #5D9CEC; 6 | @mainErrorColor: #DA4453; 7 | 8 | /* configs for base element */ 9 | @mainBorderColor: #EFEFEF; 10 | @mainLightenBorderColor: transparent; 11 | @mainBackgroundColor: #FFF; 12 | @mainDarkenBackgroundColor: #F6F6F6; 13 | 14 | /* configs for details module */ 15 | @detailsPrefixColor: @mainFontColor; 16 | 17 | /* module/base css */ 18 | #root-id .octocard-m-base img { 19 | padding: 0; 20 | width: 48px; 21 | height: 48px; 22 | border: none; 23 | } 24 | 25 | /* module/base css */ 26 | #root-id .octocard-m-details { 27 | margin: -1em -1em 10px -1em; 28 | padding: 0.5em 1em; 29 | background-color: @mainDarkenBackgroundColor; 30 | } 31 | 32 | /* module/orgs css */ 33 | #root-id .octocard-m-orgs img { 34 | padding: 0; 35 | width: 36px; 36 | height: 36px; 37 | border: none; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /themes/default.less: -------------------------------------------------------------------------------- 1 | @import "base.less"; 2 | 3 | #root-id { 4 | margin: 0 2px 2px 0; 5 | -webkit-box-shadow: 2px 2px 0 #E6E9ED; 6 | box-shadow: 2px 2px 0 #E6E9ED; 7 | } 8 | 9 | /* module/base css */ 10 | #root-id .octocard-m-base { 11 | background-image: -moz-linear-gradient(#FAFAFA, #EAEAEA); 12 | background-image: -webkit-linear-gradient(#FAFAFA, #EAEAEA); 13 | background-image: linear-gradient(#fafafa, #EAEAEA); 14 | } 15 | #root-id .octocard-m-base img { 16 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); 17 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); 18 | } 19 | -------------------------------------------------------------------------------- /themes/highcontrast.less: -------------------------------------------------------------------------------- 1 | @import "base.less"; 2 | 3 | /* configs */ 4 | @mainPrimaryColor: #000; 5 | @mainLightenPrimaryColor: rgba(0, 0, 0, .6); 6 | @mainErrorColor: #333; 7 | 8 | /* configs for base element */ 9 | @mainFontColor: #000; 10 | @mainLightenFontColor: #333; 11 | @mainLightestFontColor: #666; 12 | @mainDarkenFontColor: #000; 13 | @mainBorderColor: #000; 14 | @mainLightenBorderColor: transparent; 15 | @mainBackgroundColor: #FFF; 16 | @mainDarkenBackgroundColor: transparent; 17 | 18 | /* configs for eventsstatis module */ 19 | @eventsstatisBarColor: @mainPrimaryColor; 20 | 21 | /* module/base css */ 22 | #root-id .octocard-m-base img { 23 | padding: 0; 24 | width: 48px; 25 | height: 48px; 26 | border: none; 27 | } 28 | 29 | /* module/orgs css */ 30 | #root-id .octocard-m-orgs img { 31 | padding: 0; 32 | width: 36px; 33 | height: 36px; 34 | border: none; 35 | } 36 | -------------------------------------------------------------------------------- /themes/modern.less: -------------------------------------------------------------------------------- 1 | @import "base.less"; 2 | 3 | /* configs */ 4 | @mainPrimaryColor: #4A89DC; 5 | @mainLightenPrimaryColor: #5D9CEC; 6 | @mainErrorColor: #DA4453; 7 | 8 | /* configs for base element */ 9 | @mainBorderColor: #EFEFEF; 10 | @mainLightenBorderColor: transparent; 11 | @mainBackgroundColor: #FFF; 12 | @mainDarkenBackgroundColor: #F6F6F6; 13 | 14 | /* configs for details module */ 15 | @detailsPrefixColor: @mainFontColor; 16 | 17 | 18 | /* module/base css */ 19 | #root-id .octocard-m-base { 20 | margin: -15px -15px 10px; 21 | width: auto; 22 | } 23 | #root-id .octocard-m-base img { 24 | border: none; 25 | } 26 | /* middle module/base */ 27 | #root-id.octocard-mid .octocard-m-base { 28 | padding: 0; 29 | text-align: center; 30 | } 31 | #root-id.octocard-mid .octocard-m-base img { 32 | float: none; 33 | display: inline-block; 34 | width: 50%; 35 | height: auto; 36 | border-radius: 100%; 37 | } 38 | /* maxium module/base */ 39 | @baseImgMaxSize: 122px; 40 | #root-id.octocard-max .octocard-m-base { 41 | position: relative; 42 | padding: 0 0 0 (@baseImgMaxSize + 14px); 43 | overflow: visible; 44 | } 45 | #root-id.octocard-max .octocard-m-base img { 46 | position: absolute; 47 | top: 0; 48 | left: 0; 49 | z-index: 1; 50 | padding: 0; 51 | width: @baseImgMaxSize; 52 | height: @baseImgMaxSize; 53 | } 54 | #root-id.octocard-max .octocard-m-base + .octocard-m-details { 55 | padding-left: @baseImgMaxSize + 14px; 56 | } 57 | #root-id.octocard-max .octocard-m-base + .octocard-m-details li { 58 | float: none; 59 | width: auto; 60 | margin-right: 0; 61 | } 62 | /* minimal module/base */ 63 | #root-id.octocard-min .octocard-m-base { 64 | width: auto; 65 | margin: -13px -13px 1em; 66 | padding: 0; 67 | text-indent: 1em; 68 | } 69 | #root-id.octocard-min .octocard-m-base img { 70 | display: block; 71 | float: none; 72 | width: 100%; 73 | height: auto; 74 | margin-bottom: 1em; 75 | } 76 | #root-id.octocard-min .octocard-m-base + .octocard-m-details { 77 | padding-top: 0; 78 | } 79 | 80 | 81 | /* module/base css */ 82 | #root-id .octocard-m-details { 83 | position: relative; 84 | margin: -15px -15px 10px; 85 | padding: 0.5em 1em; 86 | width: auto; 87 | background-color: @mainDarkenBackgroundColor; 88 | } 89 | #root-id.octocard-min .octocard-m-details { 90 | margin: -13px -13px 10px; 91 | } 92 | #root-id.octocard-max .octocard-m-details { 93 | height: 21px * 3; 94 | } 95 | 96 | 97 | /* module/orgs css */ 98 | #root-id .octocard-m-orgs img { 99 | padding: 0; 100 | width: 36px; 101 | height: 36px; 102 | border: none; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /themes/night.less: -------------------------------------------------------------------------------- 1 | @import "base.less"; 2 | 3 | /* configs */ 4 | @mainPrimaryColor: #88D5C2; 5 | @mainLightenPrimaryColor: lighten(#88D5C2, 20%); 6 | @mainErrorColor: #DA4453; 7 | 8 | /* configs for base element */ 9 | @mainFontColor: #CFCFCF; 10 | @mainLightenFontColor: #999; 11 | @mainLightestFontColor: #EAEAEA; 12 | @mainDarkenFontColor: #88D5C2; 13 | @mainBorderColor: #333; 14 | @mainLightenBorderColor: rgba(207, 207, 207, 0.1); 15 | @mainBackgroundColor: #333; 16 | @mainDarkenBackgroundColor: #333; 17 | 18 | /* configs for loading module */ 19 | @loadingBackgroundColor: #333; 20 | 21 | #root-id { 22 | border-radius: 4px; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /themes/twitter-widget-dark.css: -------------------------------------------------------------------------------- 1 | /* resert css */ 2 | #root-id { 3 | position: relative; 4 | padding: 1em; 5 | min-height: 40px; 6 | margin: 0 2px 2px 0; 7 | display: block; 8 | color: #CFCFCF; 9 | font: 14px "Helvetica Neue", Arial, Helvetica, sans-serif; 10 | text-align: left; 11 | line-height: 1.5; 12 | border: 2px solid #333; 13 | background-color: #333; 14 | -webkit-box-sizing: border-box; 15 | -moz-box-sizing: border-box; 16 | box-sizing: border-box; 17 | border-radius: 4px; 18 | overflow: hidden; 19 | } 20 | #root-id.octocard-min { 21 | font-size: 12px; 22 | } 23 | #root-id span, 24 | #root-id img, 25 | #root-id ul, 26 | #root-id ol, 27 | #root-id h1, 28 | #root-id h2, 29 | #root-id li, 30 | #root-id p, 31 | #root-id div { 32 | margin: 0; 33 | padding: 0; 34 | border: none; 35 | float: none; 36 | position: static; 37 | overflow: hidden; 38 | width: auto; 39 | height: auto; 40 | line-height: inherit; 41 | color: inherit; 42 | font-size: inherit; 43 | font-weight: normal; 44 | background: none; 45 | } 46 | #root-id h1, 47 | #root-id h2 { 48 | color: #88d5c2; 49 | font-weight: bold; 50 | } 51 | #root-id li { 52 | list-style: none; 53 | } 54 | #root-id p, 55 | #root-id div, 56 | #root-id img { 57 | display: block; 58 | } 59 | #root-id a, 60 | #root-id span { 61 | display: inline; 62 | font-size: inherit; 63 | text-decoration: none; 64 | } 65 | #root-id a { 66 | color: #CFCFCF; 67 | text-decoration: none; 68 | -webkit-transition: color 0.5s ease; 69 | transition: color 0.5s ease; 70 | } 71 | #root-id a:hover { 72 | color: #88d5c2; 73 | } 74 | #root-id .octocard-m { 75 | position: relative; 76 | width: 100%; 77 | padding: 0 0 10px 0; 78 | margin: 0 0 10px 0; 79 | border-bottom: 1px solid rgba(207, 207, 207, 0.1); 80 | } 81 | #root-id .octocard-m:last-child { 82 | margin-bottom: 0; 83 | padding-bottom: 0; 84 | border-bottom: none; 85 | } 86 | #root-id .octocard-error { 87 | display: inline-block; 88 | vertical-align: middle; 89 | color: #DA4453; 90 | } 91 | #root-id .octocard-error a { 92 | margin-left: 10px; 93 | } 94 | 95 | /* loader css */ 96 | #root-id .octocard-loading { 97 | position: absolute; 98 | top: 0; 99 | left: 0; 100 | height: 100%; 101 | width: 100%; 102 | background-color: #333; 103 | } 104 | #root-id .octocard-loading-inner { 105 | position: absolute; 106 | top: 50%; 107 | left: 50%; 108 | width: 80px; 109 | height: 20px; 110 | margin-left: -40px; 111 | margin-top: -10px; 112 | overflow: visible; 113 | } 114 | #root-id .octocard-loading-0, 115 | #root-id .octocard-loading-1, 116 | #root-id .octocard-loading-2 { 117 | float: left; 118 | width: 20px; 119 | height: 100%; 120 | margin-right: 10px; 121 | background: #5D9CEC; 122 | } 123 | #root-id .octocard-loading-2 { 124 | margin-right: 0; 125 | } 126 | #root-id .octocard-loading-cur { 127 | background-color: #88d5c2; 128 | -webkit-transform: scale(1.2); 129 | -ms-transform: scale(1.2); 130 | transform: scale(1.2); 131 | } 132 | 133 | /* module/base css */ 134 | #root-id .octocard-m-base { 135 | margin: -1em -1em 10px -1em; 136 | padding: 0.5em 1em; 137 | } 138 | #root-id .octocard-m-base a { 139 | display: block; 140 | } 141 | 142 | #root-id .octocard-m-base img { 143 | float: left; 144 | margin-right: 10px; 145 | padding: 1px; 146 | width: 44px; 147 | height: 44px; 148 | border: 1px solid #DDD; 149 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); 150 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); 151 | -webkit-transition: border-color 0.5s ease; 152 | transition: border-color 0.5s ease; 153 | } 154 | #root-id .octocard-m-base a:hover img { 155 | border-color: #88d5c2; 156 | } 157 | #root-id .octocard-m-base span, 158 | #root-id .octocard-m-base h1 { 159 | overflow: hidden; 160 | line-height: 28px; 161 | font-size: 20px; 162 | white-space: nowrap; 163 | text-overflow: ellipsis; 164 | -webkit-transition: color 0.5s ease; 165 | transition: color 0.5s ease; 166 | } 167 | #root-id .octocard-m-base a:hover h1 { 168 | color: #88d5c2; 169 | } 170 | #root-id .octocard-m-base .octocard-m-base-noname { 171 | line-height: 48px; 172 | font-size: 24px; 173 | } 174 | #root-id .octocard-m-base span { 175 | display: block; 176 | font-size: 16px; 177 | line-height: 20px; 178 | } 179 | /* min base */ 180 | #root-id.octocard-min .octocard-m-base img { 181 | width: 36px; 182 | height: 36px; 183 | padding: 0; 184 | border: none; 185 | -webkit-box-shadow: none; 186 | box-shadow: none; 187 | } 188 | #root-id.octocard-min .octocard-m-base h1 { 189 | font-size: 16px; 190 | line-height: 20px; 191 | } 192 | #root-id.octocard-min .octocard-m-base .octocard-m-base-noname { 193 | font-size: 16px; 194 | line-height: 36px; 195 | } 196 | #root-id.octocard-min .octocard-m-base span { 197 | font-size: 14px; 198 | line-height: 16px; 199 | } 200 | 201 | /* module/details css */ 202 | #root-id .octocard-m-details li { 203 | white-space: nowrap; 204 | text-overflow: ellipsis; 205 | } 206 | #root-id .octocard-m-details li:before { 207 | content: "-"; 208 | float: left; 209 | margin-right: 10px; 210 | color: #AAB2BD; 211 | } 212 | #root-id .octocard-m-details a { 213 | display: block; 214 | overflow: hidden; 215 | text-overflow: ellipsis; 216 | } 217 | /* min details */ 218 | #root-id.octocard-min .octocard-m-details li:before { 219 | display: none; 220 | } 221 | /* max details */ 222 | #root-id.octocard-max .octocard-m-details li { 223 | float: left; 224 | margin-right: 2%; 225 | width: 48%; 226 | } 227 | 228 | 229 | /* module/orgs css */ 230 | #root-id .octocard-m-orgs h2 { 231 | margin-bottom: 5px; 232 | } 233 | #root-id .octocard-m-orgs ul { 234 | margin: 0; 235 | padding: 0; 236 | overflow: hidden; 237 | list-style: none; 238 | } 239 | #root-id .octocard-m-orgs li { 240 | list-style: none; 241 | float: left; 242 | margin-right: 4px; 243 | margin-bottom: 4px; 244 | } 245 | #root-id .octocard-m-orgs li:last-child { 246 | margin-right: 0; 247 | } 248 | #root-id .octocard-m-orgs a { 249 | float: left; 250 | color: inherit; 251 | } 252 | #root-id .octocard-m-orgs img { 253 | padding: 1px; 254 | width: 32px; 255 | height: 32px; 256 | border: 1px solid #ddd; 257 | } 258 | #root-id .octocard-m-orgs a:hover img { 259 | border-color: #88d5c2; 260 | } 261 | /* min orgs */ 262 | #root-id.octocard-min .octocard-m-orgs img { 263 | padding: 0; 264 | width: 24px; 265 | height: 24px; 266 | border: none; 267 | } 268 | 269 | /* module/repos css */ 270 | #root-id .octocard-m-repos ul { 271 | margin: 0; 272 | padding: 0; 273 | overflow: hidden; 274 | list-style: none; 275 | } 276 | #root-id .octocard-m-repos li { 277 | list-style: none; 278 | } 279 | #root-id .octocard-m-repos a { 280 | position: relative; 281 | display: block; 282 | color: inherit; 283 | } 284 | #root-id .octocard-m-repos a { 285 | width: 100%; 286 | } 287 | #root-id .octocard-m-repos a h2, 288 | #root-id .octocard-m-repos a p { 289 | font-size: 14px; 290 | margin-right: 50px; 291 | white-space: nowrap; 292 | text-overflow: ellipsis; 293 | } 294 | #root-id .octocard-m-repos a:hover h2 { 295 | color: #88d5c2; 296 | -webkit-transition: color 0.5s ease; 297 | transition: color 0.5s ease; 298 | } 299 | #root-id .octocard-m-repos a span { 300 | position: absolute; 301 | top: 50%; 302 | right: 0; 303 | margin-top: -10.5px; 304 | line-height: 1.5; 305 | font-size: 14px; 306 | color: #999; 307 | } 308 | /* min repos */ 309 | #root-id.octocard-min .octocard-m-repos a { 310 | margin: 0.15em 0; /* (1.5 - 1.2) / 2 = 0.15 */ 311 | line-height: 1.2; 312 | } 313 | #root-id.octocard-min .octocard-m-repos p { 314 | display: none; 315 | } 316 | #root-id.octocard-min .octocard-m-repos h2 { 317 | margin-right: 0.25em; 318 | display: inline; 319 | white-space: initial; 320 | word-wrap: break-word; 321 | } 322 | #root-id.octocard-min .octocard-m-repos span { 323 | display: inline; 324 | position: static; 325 | margin: 0; 326 | font-size: 12px; 327 | } 328 | /* max repos */ 329 | #root-id.octocard-max .octocard-m-repos h2 { 330 | font-size: 16px; 331 | } 332 | #root-id.octocard-max .octocard-m-repos p { 333 | white-space: initial; 334 | } 335 | 336 | 337 | /* module/stats css */ 338 | #root-id .octocard-m-stats ul { 339 | margin: 0; 340 | padding: 0; 341 | height: 42px; 342 | overflow: hidden; 343 | list-style: none; 344 | } 345 | #root-id .octocard-m-stats li, 346 | #root-id .octocard-m-stats a { 347 | float: left; 348 | width: 33.33%; 349 | list-style: none; 350 | color: inherit; 351 | text-align: center; 352 | } 353 | #root-id .octocard-m-stats a { 354 | width: 100%; 355 | } 356 | #root-id .octocard-m-stats a strong, 357 | #root-id .octocard-m-stats a span { 358 | display: block; 359 | width: 100%; 360 | line-height: 1.2; 361 | text-align: center; 362 | } 363 | #root-id .octocard-m-stats a:hover strong, 364 | #root-id .octocard-m-stats a:hover span { 365 | color: #88d5c2; 366 | -webkit-transition: color 0.5s ease; 367 | transition: color 0.5s ease; 368 | } 369 | #root-id .octocard-m-stats a span { 370 | margin-top: -5px; 371 | font-size: 12px; 372 | color: #999; 373 | } 374 | #root-id .octocard-m-stats a strong { 375 | font-size: 28px; 376 | font-weight: bold; 377 | color: #333; 378 | } 379 | /* min stats */ 380 | #root-id.octocard-min .octocard-m-stats ul { 381 | height: 37px; 382 | } 383 | #root-id.octocard-min .octocard-m-stats a strong { 384 | font-size: 24px; 385 | } 386 | #root-id.octocard-min .octocard-m-stats li { 387 | width: 50%; 388 | } 389 | /* max stats */ 390 | #root-id.octocard-max .octocard-m-stats li { 391 | width: 25%; 392 | } 393 | 394 | 395 | /* module/eventsStatis css */ 396 | #root-id .octocard-m-eventsstatis { 397 | position: relative; 398 | } 399 | #root-id .octocard-m-eventsstatis h2 { 400 | margin-bottom: 5px; 401 | } 402 | #root-id .octocard-m-eventsstatis-bd { 403 | overflow: hidden; 404 | width: 100%; 405 | height: 80px; 406 | } 407 | #root-id .octocard-m-eventsstatis-bar { 408 | position: relative; 409 | float: right; 410 | min-width: 3px; 411 | height: 100%; 412 | } 413 | #root-id .octocard-m-eventsstatis-bar div { 414 | position: absolute; 415 | bottom: 0; 416 | left: 0; 417 | width: 100%; 418 | text-indent: -9999px; 419 | background-color: #5D9CEC; 420 | } 421 | #root-id .octocard-m-eventsstatis-date { 422 | overflow: hidden; 423 | font-size: 12px; 424 | color: #888; 425 | } 426 | #root-id .octocard-m-eventsstatis-date-end { 427 | float: right; 428 | } 429 | /* min eventsstatis */ 430 | #octocard.octocard-min .octocard-m-eventsstatis-bd { 431 | height: 48px; 432 | } 433 | #octocard.octocard-min .octocard-m-eventsstatis-date { 434 | display: none; 435 | } 436 | 437 | 438 | /* module/footer css */ 439 | #root-id:hover .octocard-footer { 440 | display: block; 441 | } 442 | #root-id .octocard-footer { 443 | position: absolute; 444 | bottom: -1px; 445 | right: -1px; 446 | display: none; 447 | padding: 1px 4px; 448 | z-index: 1; 449 | height: 12px; 450 | text-align: center; 451 | font-size: 12px; 452 | line-height: 12px; 453 | border: 1px solid #CCC; 454 | border-top-left-radius: 4px; 455 | } 456 | --------------------------------------------------------------------------------