diff --git a/app/components/travis-cmd.js b/app/components/travis-cmd.js
new file mode 100644
index 00000000..a2a80873
--- /dev/null
+++ b/app/components/travis-cmd.js
@@ -0,0 +1,84 @@
+import Ember from 'ember';
+import config from 'travis/config/environment';
+
+let Component = Ember.Component.extend({
+ keyboard: Ember.inject.service(),
+ auth: Ember.inject.service(),
+
+ classNameBindings: ['visible'],
+ classNames: ['travis-cmd'],
+
+ didInsertElement() {
+ this.get('keyboard').bind('t', this.show.bind(this));
+ this.get('keyboard').bind('esc', 'cmd', this.hide.bind(this));
+ },
+
+ show() {
+ this.loadSlugs();
+ this.set('visible', true);
+ this.get('keyboard').setScope('cmd');
+ },
+
+ hide() {
+ this.set('visible', false);
+ this.get('keyboard').setScope(null);
+ this.set('matches', null);
+ this.set('filterString', null);
+ this.set('results', null);
+ },
+
+ loadSlugs() {
+ this.set('loading', true);
+
+ $.ajax(config.apiEndpoint + '/repos/slugs', {
+ headers: {
+ Authorization: 'token ' + this.get('auth').token(),
+ Accept: 'application/json; version=2'
+ }
+ }).then((data) => {
+ this.set('loading', false);
+ this.set('repos', data.repositories);
+ this.onLoad();
+ });
+ },
+
+ onLoad() {
+ setTimeout( () => {
+ this.$('.input').focus();
+ }, 10);
+ },
+
+ actions: {
+ filterChanged(value) {
+ let list = this.get('repos');
+
+ let options = {
+ pre: ''
+ , post: ''
+ , extract: function(el) { return el.slug; }
+ };
+
+ let results = fuzzy.filter(value, list, options);
+ let matches = results.map(function(el) { return el.string; });
+ this.set('matches', matches.slice(0, 10).join('
'));
+ this.set('results', results);
+ this.set('filterString', value);
+ },
+
+ keypress(event) {
+ if(event.keyCode === 27) {
+ this.hide();
+ } else if(event.keyCode === 13) {
+ let results;
+ if(results = this.get('results')) {
+ if(results[0]) {
+ let slug = results[0].original.slug;
+ console.log(slug);
+ }
+ }
+ }
+ }
+ }
+});
+
+export default Component;
diff --git a/app/services/keyboard.js b/app/services/keyboard.js
new file mode 100644
index 00000000..e758606e
--- /dev/null
+++ b/app/services/keyboard.js
@@ -0,0 +1,13 @@
+import Ember from 'ember';
+
+let KeyboardService = Ember.Service.extend({
+ bind(keyName, scope, callback) {
+ key(...arguments);
+ },
+
+ setScope(scope) {
+ key.setScope(scope);
+ }
+});
+
+export default KeyboardService;
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 454f557d..ed13c62d 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -66,3 +66,4 @@
@import "app/layouts/missing-notice";
@import "app/layouts/settings";
+@import "fuzzy";
diff --git a/app/styles/fuzzy.scss b/app/styles/fuzzy.scss
new file mode 100644
index 00000000..487bfcec
--- /dev/null
+++ b/app/styles/fuzzy.scss
@@ -0,0 +1,35 @@
+.travis-cmd {
+ opacity: 0.3;
+ background: #000;
+ width: 100%;
+ height: 100%;
+ z-index: 10;
+ top: 0;
+ left: 0;
+ position: fixed;
+ display: none;
+
+ .content {
+ opacity: 1;
+ }
+
+ &.visible {
+ display: block;
+ }
+
+ .content {
+ width: 400px;
+ min-height: 60px;
+ background-color: white;
+ border-radius: 10px;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ .content, .input {
+ color: black;
+ font-size: 20px;
+ }
+}
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
index c24cd689..44283f5b 100644
--- a/app/templates/application.hbs
+++ b/app/templates/application.hbs
@@ -1 +1,3 @@
{{outlet}}
+
+{{travis-cmd}}
diff --git a/app/templates/components/travis-cmd.hbs b/app/templates/components/travis-cmd.hbs
new file mode 100644
index 00000000..7fe548bb
--- /dev/null
+++ b/app/templates/components/travis-cmd.hbs
@@ -0,0 +1,15 @@
+