diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 00000000..91600595 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +service_name: travis-ci diff --git a/.eslintignore b/.eslintignore index 5c53e32e..a3c063fc 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ +coverage/ dist/ docs/ diff --git a/.gitignore b/.gitignore index e3f8c0c4..8bad676a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +coverage/ node_modules/ dist/ npm-debug.log* diff --git a/.travis.yml b/.travis.yml index c7790e9d..3af04174 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_install: before_cache: npm prune install: npm install script: ./scripts/test-ci +after_script: ./scripts/travis-after-script branches: only: - master diff --git a/README.md b/README.md index 89500394..0117308d 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,37 @@ # DocSearch -[![build status](https://travis-ci.org/algolia/docsearch.svg?branch=master)](http://travis-ci.org/algolia/docsearch) -[![NPM version](https://badge.fury.io/js/docsearch.js.svg)](http://badge.fury.io/js/docsearch.js) +The easiest way to add search to your documentation. For free. -We've created the fastest, easiest way to search within documentation. Check out our [website](https://community.algolia.com/docsearch/) to add an outstanding search to your documentation. +Check out our [website][3] to add an outstanding search to your documentation. + +[![Version][version-svg]][package-url] [![Build Status][travis-svg]][travis-url] [![Coverage Status][coveralls-svg]][coveralls-url] [![License][license-image]][license-url] [![Downloads][downloads-image]][downloads-url] + +[version-svg]: https://img.shields.io/npm/v/docsearch.js.svg?style=flat-square +[package-url]: https://npmjs.org/package/docsearch.js +[travis-svg]: https://img.shields.io/travis/algolia/docsearch/master.svg?style=flat-square +[travis-url]: https://travis-ci.org/algolia/docsearch +[coveralls-svg]: https://img.shields.io/coveralls/algolia/docsearch/master.svg?style=flat-square +[coveralls-url]: https://coveralls.io/github/algolia/docsearch?branch=docs%2Fbadges +[license-image]: http://img.shields.io/badge/license-MIT-green.svg?style=flat-square +[license-url]: LICENSE +[downloads-image]: https://img.shields.io/npm/dm/docsearch.js.svg?style=flat-square +[downloads-url]: http://npm-stat.com/charts.html?package=docsearch.js +[docsearch-website]: https://community.algolia.com/docsearch/?utm_medium=social-owned&utm_source=GitHub&utm_campaign=docsearch%20repository +[docsearch-website-docs]: https://community.algolia.com/docsearch/documentation/?utm_medium=social-owned&utm_source=GitHub&utm_campaign=docsearch%20repository + +![Eslint][4] ## Table of Contents -- [Introduction](#introduction) -- [Setup](#setup) -- [Customization](#customization) -- [Development workflow](#development-workflow) - - [Local example](#local-example) - - [Documentation website](#documentation-website) - - [MacOS](#macos) +- [Introduction][5] +- [Setup][6] +- [Customization][7] +- [Development workflow][8] + - [Local example][9] + - [Documentation website][10] + - [MacOS][11] @@ -27,7 +43,7 @@ We're scratching our own itch here. As developers, we spend a lot of time readin Not blaming anyone here. Building a good search for a documentation is a complex challenge. We happen to have a lot of experience doing that, and we want to share it with the world. For free. -Just submit the form on the [website](https://community.algolia.com/docsearch/) and we'll get back to you with what you need to integrate your new search into your website. +Just submit the form on the [website][12] and we'll get back to you with what you need to integrate your new search into your website. 1. We'll crawl your documentation pages, 2. We'll configure your search experience, @@ -51,20 +67,67 @@ docSearch({ ## Customization -To customize the look & feel of the dropdown menu, you can either: +The default colorscheme is blue and gray: - * edit the color [variables](https://github.com/algolia/docsearch/blob/master/src/styles/_variables.scss) and rebuild this project CSS (`npm run build:css`), - * or override the colors like we did in [dev/docsearch-styling.css](https://github.com/algolia/docsearch/blob/master/dev/docsearch-styling.css). +![Default colorscheme][13] + +To update the colors to suit your website, you just need to override a few +colors. Here is an example of a CSS file that you can use as a basis and that +sets white and purples colors. + +```css +/* Bottom border of each suggestion */ +.algolia-docsearch-suggestion { + border-bottom-color: #3A3DD1; +} +/* Main category headers */ +.algolia-docsearch-suggestion--category-header { + background-color: #4B54DE; +} +/* Highlighted search terms */ +.algolia-docsearch-suggestion--highlight { + color: #3A33D1; +} +/* Highligted search terms in the main category headers */ +.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight { + background-color: #4D47D5; +} +/* Currently selected suggestion */ +.aa-cursor .algolia-docsearch-suggestion--content { + color: #272296; +} +.aa-cursor .algolia-docsearch-suggestion { + background: #EBEBFB; +} + +/* For bigger screens, when displaying results in two columns */ +@media (min-width: 768px) { + /* Bottom border of each suggestion */ + .algolia-docsearch-suggestion { + border-bottom-color: #7671df; + } + /* Left column, with secondary category header */ + .algolia-docsearch-suggestion--subcategory-column { + border-right-color: #7671df; + background-color: #F2F2FF; + color: #4E4726; + } +} +``` + +Advanced users can also clone the repository, edit the [_variables.scss][14] +file and re-build the CSS file using `npm run build:css`. + ## Development workflow ### Local example -We use a simple documentation example website as a way to develop the docsearch.js library. +We use a simple documentation example website as a way to develop the docsearch library. Requirements: -- [Node.js](https://nodejs.org/en/) +- [Node.js][17] - npm@2 ```sh @@ -72,17 +135,30 @@ npm run dev # open http://localhost:8080 ``` +### Local build + +- `npm run build:js:` will transpile all the JavaScript files inside `./dist`. + We build a bundled (and bundled + minified) version for CDNs and another one + for npm +- `npm run build:css` will convert the SCSS to CSS, along with sourcemaps and + minified versions +- `npm run build:docs` will create the `./docs/documentation.md` file from the + `README.md` file, to be displayed on the website. +- `npm run build` will run all three previous commands + ### Documentation website -This is the [Jekyll](https://jekyllrb.com/) instance running at [https://community.algolia.com/docsearch](https://community.algolia.com/docsearch). +This is the [Jekyll][18] instance running at [https://community.algolia.com/docsearch](https://community.algolia.com/docsearch). Requirements: -- [Ruby](https://www.ruby-lang.org/en/) -- [Bundler](http://bundler.io/) +- [Ruby][19] +- [Bundler][20] ```sh npm run dev:docs # open http://localhost:4000/docsearch/ +# Note that it also implicitly starts another server on localhost:8080, to load +the bundled JavaScript from ``` ### MacOS @@ -92,3 +168,25 @@ If you are using `brew` and you had `brew install openssl`, you may need to conf ```sh bundle config build.eventmachine --with-cppflags=-I$(brew --prefix openssl)/include ``` + + +[1]: https://travis-ci.org/algolia/docsearch.svg?branch=master +[2]: https://badge.fury.io/js/docsearch.js.svg +[3]: https://community.algolia.com/docsearch/ +[4]: ./docs/img/showcase/example-eslint.gif +[5]: #introduction +[6]: #setup +[7]: #customization +[8]: #development-workflow +[9]: #local-example +[10]: #documentation-website +[11]: #macos +[12]: https://community.algolia.com/docsearch/ +[13]: ./docs/img/default-colorscheme.png +[14]: https://github.com/algolia/docsearch/blob/master/src/styles/_variables.scss +[15]: https://github.com/algolia/docsearch/blob/master/dev/docsearch-styling.css +[16]: https://github.com/algolia/docsearch/blob/master/src/styles/_variables.scss +[17]: https://nodejs.org/en/ +[18]: https://jekyllrb.com/ +[19]: https://www.ruby-lang.org/en/ +[20]: http://bundler.io/ diff --git a/docs/img/default-colorscheme.png b/docs/img/default-colorscheme.png new file mode 100644 index 00000000..5bac04fd Binary files /dev/null and b/docs/img/default-colorscheme.png differ diff --git a/package.json b/package.json index 5c9d7cca..c59bf327 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "lint": "eslint .", "test": "BABEL_ENV=test mocha --reporter dot ./test/helpers.js ./test/*-test.js", "test:watch": "BABEL_ENV=test mocha --reporter min --watch ./test/helpers.js ./test/*-test.js", + "test:coverage": "./scripts/test-coverage", "gh-pages": "./scripts/gh-pages" }, "author": "Algolia (https://github.com/algolia/)", @@ -27,9 +28,11 @@ "babel": "^5.8.29", "babel-core": "^5.8.29", "babel-eslint": "^4.1.3", + "babel-istanbul": "^0.5.9", "babel-loader": "^5.3.2", "babel-plugin-rewire": "^0.1.22", "conventional-changelog": "^0.5.1", + "coveralls": "^2.11.6", "cssnano": "^3.4.0", "doctoc": "^0.15.0", "eslint": "^1.6.0", @@ -43,6 +46,7 @@ "json": "^9.0.3", "mocha": "^2.3.4", "mocha-jsdom": "^1.0.0", + "mocha-lcov-reporter": "^1.0.0", "mversion": "^1.10.1", "nd": "^1.2.0", "node-sass": "^3.4.2", diff --git a/scripts/test-ci b/scripts/test-ci index 40003aab..8cd42e53 100755 --- a/scripts/test-ci +++ b/scripts/test-ci @@ -3,12 +3,12 @@ set -ev # exit when error ./scripts/validate-pr-done-on-develop -npm test +npm run test:coverage npm prune npm run shrinkwrap --dev NODE_ENV=production npm run build ./scripts/validate-commit-msgs -if [ $TRAVIS_PULL_REQUEST == 'false' ] && [ $TRAVIS_BRANCH == 'master' ]; then +if [ "$TRAVIS_PULL_REQUEST" == 'false' ] && [ "$TRAVIS_BRANCH" == 'master' ]; then ./scripts/finish-release fi diff --git a/scripts/test-coverage b/scripts/test-coverage new file mode 100755 index 00000000..f80edff1 --- /dev/null +++ b/scripts/test-coverage @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Will run the test and export the coverage information in ./coverage +# This file will then be read by Travis to push it to Coveralls +# +# The command is long and was quite hard to write correctly. +# We need babel-istanbul and not instanbul +# We need the _mocha and not mocha +# We need to use full path for each binaries +# We need to run everything through babel-node + +npm_bin="$(npm bin)" +babel_istanbul_bin="${npm_bin}/babel-istanbul" +mocha_bin="${npm_bin}/_mocha" + +BABEL_ENV=test \ + babel-node "$babel_istanbul_bin" cover "$mocha_bin" \ + --report lcov -- \ + -R spec --reporter dot \ + ./test/helpers.js ./test/*-test.js diff --git a/scripts/travis-after-script b/scripts/travis-after-script new file mode 100755 index 00000000..0de1d0f5 --- /dev/null +++ b/scripts/travis-after-script @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# Will push coverage info to coveralls. Should be ran from Travis, in the +# `after_script` section + +$(npm bin)/coveralls < ./coverage/lcov.info diff --git a/src/lib/DocSearch.js b/src/lib/DocSearch.js index 7017b765..a1bdf050 100644 --- a/src/lib/DocSearch.js +++ b/src/lib/DocSearch.js @@ -54,7 +54,7 @@ class DocSearch { this.autocomplete = autocomplete(this.input, autocompleteOptions, [{ source: this.getAutocompleteSource(), templates: { - suggestion: this.getSuggestionTemplate(), + suggestion: DocSearch.getSuggestionTemplate(), footer: templates.footer } }]); @@ -154,7 +154,7 @@ class DocSearch { }); } - getSuggestionTemplate() { + static getSuggestionTemplate() { const template = Hogan.compile(templates.suggestion); return (suggestion) => { return template.render(suggestion); diff --git a/test/DocSearch-test.js b/test/DocSearch-test.js index 11b6a62a..7b3a9649 100644 --- a/test/DocSearch-test.js +++ b/test/DocSearch-test.js @@ -686,5 +686,80 @@ describe('DocSearch', () => { // Then expect(actual[0].text).toEqual('…lorem foo bar ipsum.'); }); + it('should add the anchor to the url if one is set', () => { + // Given + let input = [{ + hierarchy: { + lvl0: 'Ruby', + lvl1: 'API', + lvl2: null, + lvl3: null, + lvl4: null, + lvl5: null + }, + content: 'foo bar', + url: 'http://foo.bar/', + anchor: 'anchor' + }]; + + // When + let actual = DocSearch.formatHits(input); + + // Then + expect(actual[0].url).toEqual('http://foo.bar/#anchor'); + }); + }); + + describe('getSuggestionTemplate', () => { + beforeEach(() => { + let templates = { + suggestion: '
' + }; + DocSearch.__Rewire__('templates', templates); + }); + afterEach(() => { + DocSearch.__ResetDependency__('templates'); + }); + it('should return a function', () => { + // Given + + // When + let actual = DocSearch.getSuggestionTemplate(); + + // Then + expect(actual).toBeA('function'); + }); + describe('returned function', () => { + let Hogan; + let render; + beforeEach(() => { + render = sinon.spy(); + Hogan = { + compile: sinon.stub().returns({render}) + }; + DocSearch.__Rewire__('Hogan', Hogan); + }); + it('should compile the suggestion template', () => { + // Given + + // When + DocSearch.getSuggestionTemplate(); + + // Then + expect(Hogan.compile.calledOnce).toBe(true); + expect(Hogan.compile.calledWith('
')).toBe(true); + }); + it('should call render on a Hogan template', () => { + // Given + let actual = DocSearch.getSuggestionTemplate(); + + // When + actual('foo'); + + // Then + expect(render.calledOnce).toBe(true); + expect(render.calledWith('foo')).toBe(true); + }); + }); }); });