├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── config.yaml ├── package.json ├── scripts ├── build.js ├── config.js └── make-db.js ├── static └── sorttable.js └── templates ├── badges.jade ├── index.jade ├── layout.jade ├── maintainers.jade ├── projects.jade └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store* 3 | *.log 4 | *.gz 5 | 6 | node_modules 7 | coverage 8 | 9 | # autogenerated files ignored in repo-utils/badgeboard 10 | # to avoid downstream merge conflicts 11 | # 12 | # remove this when you're creating a real badgeboard 13 | /index.html 14 | /scripts/db.json 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 The jshttp team and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NODE ?= node 2 | NPM ?= npm 3 | 4 | index.html: config.yaml node_modules scripts/* templates/* scripts/db.json 5 | @${NODE} scripts/build.js 6 | 7 | # command to rebuild db.json, will be executed 8 | # only once if scripts/db.json isn't present 9 | scripts/db.json: 10 | @${NODE} --harmony scripts/make-db.js 11 | 12 | # `make db` will force rebuilding db.json even if it exists 13 | db: 14 | @${MAKE} --always-make scripts/db.json 15 | 16 | # removes autogenerated files 17 | clean: 18 | rm scripts/db.json index.html 19 | 20 | # install all packages if they don't exist (repo just been cloned) 21 | node_modules: package.json 22 | @${NPM} install . 23 | 24 | help: 25 | @echo 'make - make index.html' 26 | @echo 'make db - download stuff from other servers' 27 | @echo 'make clean - remove autogenerated files' 28 | @echo 'make help - print this message (try that again)' 29 | 30 | .PHONY: db clean help 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Pulling from here: 2 | 3 | ```sh 4 | ~/your-org.github.io$ git pull https://github.com/repo-utils/badgeboard.git 5 | ~/your-org.github.io$ make ; make db 6 | ~/your-org.github.io$ git commit index.html src/db.json -m 'rebuild' 7 | ~/your-org.github.io$ git push 8 | ``` 9 | 10 | You'll probably need to resolve merge conflicts after you do `git pull`. 11 | 12 | ## Creating new badgeboard: 13 | 14 | 1\. clone this repo 15 | 16 | ```sh 17 | ~$ git clone https://github.com/repo-utils/badgeboard.git your-org.github.io 18 | ``` 19 | 20 | 2\. change `config.yaml` 21 | 22 | 3\. change `.gitignore`, unignore autogenerated files, see comments there. 23 | Specifically, you want to uncomment `index.html` from the `.gitignore`. 24 | 25 | 4\. make it: 26 | 27 | ```sh 28 | ~/your-org.github.io$ make 29 | ``` 30 | 31 | 5\. test it: 32 | 33 | ```sh 34 | ~/your-org.github.io$ firefox index.html 35 | ``` 36 | 37 | 6\. add autogenerated files so they will appear on github pages: 38 | 39 | ```sh 40 | ~/your-org.github.io$ git add src/db.json index.html 41 | ~/your-org.github.io$ git commit src/db.json index.html -m 'rebuild' 42 | ``` 43 | 44 | ## Deployment Methods 45 | 46 | There are two ways to deploy the badge board. 47 | The first is to deploy it at `https://.github.io`. 48 | To do so, simply push your badgeboard to `https://github.com//.github.io`. 49 | 50 | The second way is to deploy it to a URL like `https://.github.io/badgeboard`. 51 | You may prefer this method if you are already have a page for your GitHub organization. 52 | To do so, push your badgeboard to `https://github.com//badgeboard` 53 | and change the default branch to `gh-pages` instead of `master`. 54 | Of course, you don't have to name the repository `badgeboard` - you can name it whatever you'd like. 55 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | # organization name, it's used to get github repo url, also in page title 2 | name: jshttp 3 | 4 | # badge style, can be "flat" or "" 5 | # see https://badgen.net/ for details 6 | badge_style: flat 7 | 8 | # meta headers in html 9 | title: BadgeBoard 10 | description: project status at a glance 11 | keywords: badgeboard, repo-utils 12 | 13 | # list of projects, this will be sorted by name; 14 | # every package is either string or object 15 | projects: 16 | - on-headers 17 | - on-finished 18 | - vary 19 | - mime-db: 20 | node: 0.6 # you can override stuff from db.json here, i.e. node version 21 | 22 | # list of maintainers, this won't be sorted 23 | maintainers: 24 | - name: Doug Wilson 25 | github: dougwilson # github account, required: we link to it 26 | npm: dougwilson # npm account, required to determine lead maintainer 27 | twitter: blipsofadoug # twitter account, optional 28 | email: doug@somethingdoug.com 29 | 30 | - name: Jonathan Ong 31 | github: jonathanong 32 | npm: jongleberry 33 | twitter: jongleberry 34 | email: me@jongleberry.com 35 | 36 | # if gravatar is attached to an email different from specified above, 37 | # add md5 of it here: 38 | avatar: 6e33cc0412b61cc01daac23c8989003c 39 | 40 | - name: Jeremiah Senkpiel 41 | github: fishrock123 42 | npm: fishrock123 43 | twitter: fishrock123 44 | email: fishrock123@rocketmail.com 45 | 46 | - name: Alex Kocharin 47 | github: rlidwka 48 | npm: rlidwka 49 | twitter: rlidwka 50 | email: alex@kocharin.ru 51 | 52 | # this determines what info will be fetched with `make db`; 53 | # you can comment out stuff to reduce number of http requests 54 | db.json: 55 | projects: 56 | - node # node version, it's the lowest version from .travis.yml 57 | - description # package description from package.json (from npm registry) 58 | - maintainer # maintainer npm account (= _npmUser of last published ver) 59 | maintainers: 60 | - packages # amount of packages this npm user has 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "badgeboard", 3 | "description": "", 4 | "private": true, 5 | "version": "1.0.0", 6 | "author": { 7 | "name": "Jonathan Ong", 8 | "email": "me@jongleberry.com", 9 | "url": "http://jongleberry.com", 10 | "twitter": "https://twitter.com/jongleberry" 11 | }, 12 | "license": "MIT", 13 | "repository": "repo-utils/badgeboard", 14 | "devDependencies": { 15 | "co": ">= 4.6.0 < 5", 16 | "gnode": "0.1.2", 17 | "jade": ">= 1.11.0 < 2", 18 | "js-yaml": ">= 3.13.1 < 4", 19 | "request": ">= 2.76.0 < 3" 20 | }, 21 | "scripts": { 22 | "build": "node scripts/build.js", 23 | "build-db": "gnode scripts/make-db.js" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | 2 | var fs = require('fs') 3 | var path = require('path') 4 | var jade = require('jade') 5 | 6 | var index = path.join(__dirname, '../templates/index.jade') 7 | var out = path.join(__dirname, '../index.html') 8 | var config = require('./config') 9 | 10 | var src = fs.readFileSync(index, 'utf8') 11 | 12 | var fn = jade.compile(src, { 13 | compileDebug: false, 14 | filename: index, 15 | pretty: true 16 | }) 17 | 18 | var html = fn(config) 19 | 20 | fs.writeFileSync(out, html) 21 | -------------------------------------------------------------------------------- /scripts/config.js: -------------------------------------------------------------------------------- 1 | // this module merges together config file and automatically 2 | // fetched data, and normalizes everything after that 3 | 4 | var yaml = require('js-yaml') 5 | var fs = require('fs') 6 | var path = require('path') 7 | var crypto = require('crypto') 8 | var config = fs.readFileSync(path.join(__dirname, '../config.yaml'), 'utf8') 9 | module.exports = config = yaml.safeLoad(config) 10 | 11 | try { 12 | // this file might not exist if we're 13 | // building db.json for the first time 14 | var db = require('./db.json') 15 | } catch(_) { 16 | db = {projects: {}, maintainers: {}} 17 | } 18 | 19 | // 20 | // maintainers data 21 | // 22 | config.maintainers = (config.maintainers || []).map(function(maintainer) { 23 | if (db.maintainers[maintainer.npm]) 24 | mixin(maintainer, db.maintainers[maintainer.npm]) 25 | 26 | maintainer.avatar = maintainer.avatar 27 | || crypto.createHash('md5').update(maintainer.email).digest('hex') 28 | return maintainer 29 | }) 30 | 31 | // 32 | // projects data 33 | // 34 | config.projects = (config.projects || []).map(function(project) { 35 | if (typeof(project) === 'string') project = {name: project} 36 | 37 | // dealing with a bit weird edge-case in config file 38 | // {vary: {blah: blah}} -> {name: vary, blah: blah} 39 | var keys = Object.keys(project) 40 | if (keys.length === 1 && !project.name) { 41 | project = project[keys[0]] 42 | project.name = keys[0] 43 | } 44 | 45 | if (db.projects[project.name]) 46 | mixin(project, db.projects[project.name]) 47 | 48 | // normalize 49 | project.npm = project.npm || project.name.toLowerCase() 50 | project.repo = project.repo || (config.name + '/' + project.name) 51 | project.maintainer = config.maintainers.filter(function(m) { 52 | return m.npm === project.maintainer 53 | })[0] 54 | return project 55 | }).sort(function(a, b) { 56 | return a.name > b.name ? 1 : -1 57 | }) 58 | 59 | // 60 | // list of strings -> object 61 | // i.e. ['foo', 'bar', 'baz'] -> {foo: true, bar: true, baz: true} 62 | // 63 | if (config['db.json']) { 64 | for (var k in config['db.json']) { 65 | if (Array.isArray(config['db.json'][k])) { 66 | var t = {} 67 | config['db.json'][k].forEach(function(v) { 68 | t[v] = true 69 | }) 70 | config['db.json'][k] = t 71 | } 72 | } 73 | } 74 | 75 | // 76 | // helpers 77 | // 78 | function mixin(obj, stuff) { 79 | Object.keys(stuff).forEach(function(i) { 80 | if (typeof(obj[i]) === 'object') { 81 | mixin(obj[i], stuff[i]) 82 | } else if (!obj[i]) { 83 | obj[i] = stuff[i] 84 | } 85 | }) 86 | } 87 | 88 | -------------------------------------------------------------------------------- /scripts/make-db.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/node --harmony 2 | 3 | // This script fetches different info from remote servers. 4 | // 5 | // It could take a lot of time later, so it's inadvisable 6 | // to run it on every build. 7 | 8 | var request = require('request') 9 | var YAML = require('js-yaml') 10 | 11 | var data = { 12 | projects: {}, 13 | maintainers: {}, 14 | } 15 | var config = require('./config') 16 | var maintainersDB = config.maintainers 17 | maintainersDB.forEach(function (maintainer) { 18 | data.maintainers[maintainer.npm] = {} 19 | }) 20 | var projectsDB = config.projects 21 | projectsDB.forEach(function (project) { 22 | data.projects[project.name] = {} 23 | }) 24 | 25 | require('co')(function *() { 26 | yield [getInfoFromNpm, getInfoFromGithub, getMaintainersInfo] 27 | 28 | // it's pretty-printed only for git diffs, don't edit that manually 29 | var json = JSON.stringify(data, function(k, obj) { 30 | if (typeof obj !== 'object') return obj 31 | var ret = Object.create(null) 32 | if (k === "") { 33 | ret['//1'] = "Fair Warning: This file is autogenerated;" 34 | ret['//2'] = "you're free to change it as you like," 35 | ret['//3'] = "but it will be overwritten on the next build." 36 | } 37 | Object.keys(obj).sort().forEach(function(i) { ret[i] = obj[i] }) 38 | return ret 39 | }, 2) 40 | require('fs').writeFileSync(__dirname + '/db.json', json) 41 | }).then() 42 | 43 | 44 | // 45 | // Generators 46 | // 47 | 48 | function *getNpmInfo(pkg) { 49 | return JSON.parse(yield get('https://registry.npmjs.org/' + pkg)) 50 | } 51 | 52 | function *getTravis(repo) { 53 | var result = yield get('https://raw.githubusercontent.com/' 54 | + repo + '/master/.travis.yml') 55 | try { 56 | return YAML.safeLoad(result) 57 | } catch(_) { 58 | return {} 59 | } 60 | } 61 | 62 | function *getUserInfo(user) { 63 | return JSON.parse(yield get('https://registry.npmjs.org/' 64 | + '_users/org.couchdb.user:' + user)) 65 | } 66 | 67 | function *getOwnedPackages(user) { 68 | var data = yield get('https://skimdb.npmjs.com/' 69 | + 'registry/_design/app/_view/browseAuthors' 70 | + '?startkey=' + escapeJSON([user]) 71 | + '&endkey=' + escapeJSON([user, {}]) 72 | + '&group_level=1') // set group_level=2 for list 73 | return JSON.parse(data).rows[0].value 74 | } 75 | 76 | function *getMaintainersInfo() { 77 | for (var name in data.maintainers) { 78 | var mData = data.maintainers[name] 79 | if (config['db.json'].maintainers.packages) 80 | mData.packages = yield getOwnedPackages(name) 81 | 82 | //if (config['db.json'].maintainers.avatar) 83 | // mData.avatar = (yield getUserInfo(name)).avatar 84 | } 85 | } 86 | 87 | function *getInfoFromNpm() { 88 | if (!config['db.json'].projects.maintainer 89 | && !config['db.json'].projects.description) return 90 | 91 | for (var i=0; i ' + url.split('?')[0]) 120 | request.get({ 121 | url: url, 122 | encoding: 'utf8', 123 | }, function(err, res, body) { 124 | cb(err, body) 125 | }) 126 | } 127 | } 128 | 129 | // for couchdb 130 | function escapeJSON(data) { 131 | return encodeURIComponent(JSON.stringify(data)) 132 | } 133 | 134 | function versionSort(a, b) { 135 | a = String(a).split('.') 136 | b = String(b).split('.') 137 | if (a[0] != b[0]) return a[0] - b[0] 138 | return a[1] - b[1] 139 | } 140 | -------------------------------------------------------------------------------- /static/sorttable.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repo-utils/badgeboard/fe507cdabbd053d797706bbe922d8c9233b4a475/static/sorttable.js -------------------------------------------------------------------------------- /templates/badges.jade: -------------------------------------------------------------------------------- 1 | 2 | mixin badge(url) 3 | img(src='https://' + (badge_style ? badge_style + '.' : '') + 'badgen.net/' + url.replace(/^\//, '')) 4 | 5 | mixin badge-npm(name) 6 | a(href='https://www.npmjs.org/package/' + name) 7 | +badge('/npm/v/' + name) 8 | 9 | mixin badge-version(version) 10 | //- probably want different colors for different versions 11 | a(href='http://nodejs.org/download/') 12 | if ((version_cmp = Number(version.toString().split('.').slice(0, 2).map(function (n) { return (n < 10 ? '0' : '') + n }).join('.')))) 13 | +badge('/badge/node.js/>=%20' + version + '/' + 14 | (version_cmp >= 10.0 ? 'orange' : version_cmp >= 8.0 ? 'yellow' : 'green')) 15 | else 16 | +badge('/badge/node.js/N%2FA/grey') 17 | 18 | mixin badge-david(repo) 19 | a(href='https://david-dm.org/' + repo) 20 | +badge('/david/dep/' + repo) 21 | 22 | mixin badge-travis(repo) 23 | a(href='https://travis-ci.org/' + repo) 24 | +badge('/travis/' + repo + '/master') 25 | 26 | mixin badge-coverage(repo) 27 | a(href='https://coveralls.io/r/' + repo) 28 | +badge('/coveralls/c/github/' + repo + '/master') 29 | 30 | mixin badge-packagephobia(npm) 31 | a(href='https://packagephobia.now.sh/result?p=' + npm) 32 | +badge('/packagephobia/install/' + npm) 33 | 34 | mixin badge-downloads(npm) 35 | a(href='https://npmjs.org/package/' + npm) 36 | +badge('/npm/dm/' + npm) 37 | -------------------------------------------------------------------------------- /templates/index.jade: -------------------------------------------------------------------------------- 1 | 2 | include projects 3 | include maintainers 4 | 5 | extends layout 6 | 7 | block body 8 | section 9 | h1 Projects 10 | .table-wrap 11 | +projects(projects) 12 | 13 | section 14 | h1 Team 15 | .table-wrap 16 | +maintainers(maintainers) 17 | -------------------------------------------------------------------------------- /templates/layout.jade: -------------------------------------------------------------------------------- 1 | doctype 2 | html.no-js 3 | head 4 | meta(charset='utf-8') 5 | meta(http-equiv='X-UA-Compatible', content='IE=edge') 6 | if (typeof(title) !== 'undefined') 7 | title= title 8 | else 9 | title= name 10 | meta(name='description', content=description || '') 11 | meta(name='keywords', content=keywords || '') 12 | meta(name='viewport', content='width=device-width, initial-scale=1') 13 | link(href='https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css', rel='stylesheet') 14 | style 15 | include:uglify-css style.css 16 | script(src='static/sorttable.js') 17 | body 18 | .navbar(role='navigation') 19 | .navbar-header 20 | a.navbar-brand.logo(href='https://github.com/' + name)= title 21 | .navbar-brand.manifesto 22 | span= description 23 | 24 | block body 25 | 26 | //- Google Analytics: change UA-XXXXX-X to be your site's ID. 27 | //- 28 | script 29 | (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]= 30 | function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date; 31 | e=o.createElement(i);r=o.getElementsByTagName(i)[0]; 32 | e.src='//www.google-analytics.com/analytics.js'; 33 | r.parentNode.insertBefore(e,r)}(window,document,'script','ga')); 34 | ga('create','UA-XXXXX-X');ga('send','pageview'); 35 | footer 36 | //- please, don't remove this unless you have a good reason to 37 | | This web page was created using 38 | | #{' '} 39 | a(href='https://github.com/repo-utils/badgeboard') repo-utils/badgeboard 40 | | #{' '} 41 | | generator. You can use it to create a similar badgeboard for your 42 | | stuff. 43 | -------------------------------------------------------------------------------- /templates/maintainers.jade: -------------------------------------------------------------------------------- 1 | 2 | include badges 3 | 4 | mixin avatar(emailmd5, size) 5 | img(src='https://secure.gravatar.com/avatar/' + emailmd5 + '?s=' + size + '&d=retro', width=size, height=size, style='vertical-align:middle') 6 | 7 | mixin maintainers(maintainers) 8 | table.table.table-striped 9 | tbody 10 | for maintainer in maintainers 11 | +maintainer-row(maintainer) 12 | 13 | mixin maintainer-row(maintainer) 14 | tr 15 | td 16 | +avatar(maintainer.avatar, 20) 17 | td 18 | a(href='https://github.com/' + maintainer.github)= maintainer.name 19 | td 20 | if maintainer.twitter 21 | a(href='https://twitter.com/' + maintainer.twitter)= '@' + maintainer.twitter 22 | td 23 | a(href='https://www.npmjs.org/~' + maintainer.npm) 24 | +badge('/badge/packages/' + Number(maintainer.packages) + '/blue') 25 | -------------------------------------------------------------------------------- /templates/projects.jade: -------------------------------------------------------------------------------- 1 | 2 | include badges 3 | 4 | mixin projects(projects) 5 | table.table.sortable.table-striped.projects-table 6 | thead 7 | tr 8 | th.sorttable_sorted 9 | | Project 10 | //- marker means "sorted by default"; should be in .js, but I'm lazy 11 | span#sorttable_sortfwdind  ▾ 12 | th Maintainer 13 | th.sorttable_nosort.empty(colspan='6') 14 | tbody 15 | for project in projects 16 | +project-row(project) 17 | 18 | mixin project-row(project) 19 | tr 20 | td: +project(project) 21 | td: +maintainer(project.maintainer) 22 | td: +badge-npm(project.npm) 23 | td: +badge-version(project.node) 24 | td: +badge-packagephobia(project.npm) 25 | td: +badge-travis(project.repo) 26 | td: +badge-coverage(project.repo) 27 | td: +badge-david(project.repo) 28 | td: +badge-downloads(project.npm) 29 | 30 | mixin project(project) 31 | a(title=project.description, href='https://github.com/' + project.repo)= project.name 32 | 33 | mixin maintainer(person) 34 | if typeof(person) === 'object' && person != null 35 | a(href='https://github.com/' + person.github)= person.name 36 | -------------------------------------------------------------------------------- /templates/style.css: -------------------------------------------------------------------------------- 1 | 2 | section > h1 { 3 | padding-left: 20px; 4 | } 5 | 6 | section { 7 | margin-bottom: 20px; 8 | } 9 | 10 | footer { 11 | border-top: 1px solid #ddd; 12 | padding: 10px 20px; 13 | font-size: 12px; 14 | } 15 | 16 | .table-wrap { 17 | overflow-x: auto; 18 | } 19 | 20 | .table { 21 | margin-bottom: 0; 22 | } 23 | 24 | .table td { 25 | white-space: nowrap; 26 | } 27 | 28 | .table > tbody > tr > td:first-child, 29 | .table > thead > tr > th:first-child { 30 | padding-left: 20px; 31 | } 32 | 33 | .table > tbody > tr > td:last-child, 34 | .table > thead > tr > th:last-child { 35 | padding-right: 20px; 36 | width: 100%; 37 | } 38 | 39 | table.sortable > thead > tr > th { 40 | cursor: pointer; 41 | } 42 | table.sortable > thead > tr > th:hover { 43 | color: #2a6496; 44 | } 45 | 46 | table.sortable > thead > tr > th.empty { 47 | cursor: default; 48 | } 49 | 50 | .navbar.navbar { 51 | border-radius: 0; 52 | background-color: #f0f0f0; 53 | background-image: -moz-linear-gradient(#fafafa, #f0f0f0); 54 | background-image: -webkit-linear-gradient(#fafafa, #f0f0f0); 55 | background-image: linear-gradient(#fafafa, #f0f0f0); 56 | background-repeat: repeat-x; 57 | border-bottom: 1px solid #ddd; 58 | } 59 | 60 | .manifesto { 61 | padding: 25px 0px 15px; 62 | font-size: 14px; 63 | } 64 | 65 | .navbar-header { 66 | width: 100%; 67 | } 68 | 69 | .navbar { 70 | min-height: 40px; 71 | } 72 | 73 | .navbar-brand { 74 | height: 40px; 75 | padding: 10px; 76 | } 77 | 78 | a.navbar-brand { 79 | color: #333; 80 | } 81 | 82 | a.navbar-brand:hover, a.navbar-brand:focus { 83 | color: #2a6496; 84 | } 85 | 86 | @media (max-width: 480px) { 87 | .manifesto { 88 | clear: left; 89 | height: auto; 90 | padding: 7px 0; 91 | padding-left: 20px; 92 | } 93 | } 94 | 95 | @media (min-width: 481px) { 96 | .manifesto span:before { 97 | content: "\2014"; 98 | padding-right: 10px; 99 | } 100 | 101 | .manifesto { 102 | padding-left: 0; 103 | } 104 | } 105 | --------------------------------------------------------------------------------