├── .bowerrc
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .jshintrc
├── Gruntfile.js
├── README.md
├── app
├── _locales
│ └── en
│ │ └── messages.json
├── images
│ ├── icon-128.png
│ ├── icon-16.png
│ └── icon-48.png
├── manifest.json
├── pages
│ ├── notice.html
│ └── permission.html
├── scripts
│ ├── background.js
│ ├── chromereload.js
│ ├── contentscript.js
│ └── notice.js
└── styles
│ ├── background.css
│ └── main.css
├── bower.json
├── package.json
├── promo
├── large-tile.png
├── marquee.png
├── screenshot.png
└── small-tile.png
└── test
├── .bowerrc
├── bower.json
├── index.html
└── spec
└── test.js
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "app/bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 4
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | temp
3 | .tmp
4 | dist
5 | .sass-cache
6 | app/bower_components
7 | test/bower_components
8 | package
9 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 4,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true,
21 | "globals" : {
22 | "chrome": true
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | // Generated on 2015-01-03 using generator-chrome-extension 0.2.9
2 | 'use strict';
3 |
4 | // # Globbing
5 | // for performance reasons we're only matching one level down:
6 | // 'test/spec/{,*/}*.js'
7 | // use this if you want to recursively match all subfolders:
8 | // 'test/spec/**/*.js'
9 |
10 | module.exports = function (grunt) {
11 |
12 | // Load grunt tasks automatically
13 | require('load-grunt-tasks')(grunt);
14 |
15 | // Time how long tasks take. Can help when optimizing build times
16 | require('time-grunt')(grunt);
17 |
18 | // Configurable paths
19 | var config = {
20 | app: 'app',
21 | dist: 'dist'
22 | };
23 |
24 | grunt.initConfig({
25 |
26 | // Project settings
27 | config: config,
28 |
29 | // Watches files for changes and runs tasks based on the changed files
30 | watch: {
31 | bower: {
32 | files: ['bower.json'],
33 | tasks: ['bowerInstall']
34 | },
35 | js: {
36 | files: ['<%= config.app %>/scripts/{,*/}*.js'],
37 | // tasks: ['jshint'],
38 | options: {
39 | livereload: true
40 | }
41 | },
42 | gruntfile: {
43 | files: ['Gruntfile.js']
44 | },
45 | styles: {
46 | files: ['<%= config.app %>/styles/{,*/}*.css'],
47 | tasks: [],
48 | options: {
49 | livereload: true
50 | }
51 | },
52 | livereload: {
53 | options: {
54 | livereload: '<%= connect.options.livereload %>'
55 | },
56 | files: [
57 | '<%= config.app %>/*.html',
58 | '<%= config.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
59 | '<%= config.app %>/manifest.json',
60 | '<%= config.app %>/_locales/{,*/}*.json'
61 | ]
62 | }
63 | },
64 |
65 | // Grunt server and debug server setting
66 | connect: {
67 | options: {
68 | port: 9000,
69 | livereload: 35729,
70 | // change this to '0.0.0.0' to access the server from outside
71 | hostname: 'localhost'
72 | },
73 | chrome: {
74 | options: {
75 | open: false,
76 | base: [
77 | '<%= config.app %>'
78 | ]
79 | }
80 | },
81 | test: {
82 | options: {
83 | open: false,
84 | base: [
85 | 'test',
86 | '<%= config.app %>'
87 | ]
88 | }
89 | }
90 | },
91 |
92 | // Empties folders to start fresh
93 | clean: {
94 | chrome: {
95 | },
96 | dist: {
97 | files: [{
98 | dot: true,
99 | src: [
100 | '<%= config.dist %>/*',
101 | '!<%= config.dist %>/.git*'
102 | ]
103 | }]
104 | }
105 | },
106 |
107 | // Make sure code styles are up to par and there are no obvious mistakes
108 | jshint: {
109 | options: {
110 | jshintrc: '.jshintrc',
111 | reporter: require('jshint-stylish')
112 | },
113 | all: [
114 | 'Gruntfile.js',
115 | '<%= config.app %>/scripts/{,*/}*.js',
116 | '!<%= config.app %>/scripts/vendor/*',
117 | 'test/spec/{,*/}*.js'
118 | ]
119 | },
120 | mocha: {
121 | all: {
122 | options: {
123 | run: true,
124 | urls: ['http://localhost:<%= connect.options.port %>/index.html']
125 | }
126 | }
127 | },
128 |
129 | // Automatically inject Bower components into the HTML file
130 | bowerInstall: {
131 | app: {
132 | src: [
133 | '<%= config.app %>/*.html'
134 | ]
135 | }
136 | },
137 |
138 | // Reads HTML for usemin blocks to enable smart builds that automatically
139 | // concat, minify and revision files. Creates configurations in memory so
140 | // additional tasks can operate on them
141 | useminPrepare: {
142 | options: {
143 | dest: '<%= config.dist %>'
144 | },
145 | html: [
146 | '<%= config.app %>/popup.html',
147 | '<%= config.app %>/options.html'
148 | ]
149 | },
150 |
151 | // Performs rewrites based on rev and the useminPrepare configuration
152 | usemin: {
153 | options: {
154 | assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
155 | },
156 | html: ['<%= config.dist %>/{,*/}*.html'],
157 | css: ['<%= config.dist %>/styles/{,*/}*.css']
158 | },
159 |
160 | // The following *-min tasks produce minifies files in the dist folder
161 | imagemin: {
162 | dist: {
163 | files: [{
164 | expand: true,
165 | cwd: '<%= config.app %>/images',
166 | src: '{,*/}*.{gif,jpeg,jpg,png}',
167 | dest: '<%= config.dist %>/images'
168 | }]
169 | }
170 | },
171 |
172 | svgmin: {
173 | dist: {
174 | files: [{
175 | expand: true,
176 | cwd: '<%= config.app %>/images',
177 | src: '{,*/}*.svg',
178 | dest: '<%= config.dist %>/images'
179 | }]
180 | }
181 | },
182 |
183 | htmlmin: {
184 | dist: {
185 | options: {
186 | // removeCommentsFromCDATA: true,
187 | // collapseWhitespace: true,
188 | // collapseBooleanAttributes: true,
189 | // removeAttributeQuotes: true,
190 | // removeRedundantAttributes: true,
191 | // useShortDoctype: true,
192 | // removeEmptyAttributes: true,
193 | // removeOptionalTags: true
194 | },
195 | files: [{
196 | expand: true,
197 | cwd: '<%= config.app %>',
198 | src: '*.html',
199 | dest: '<%= config.dist %>'
200 | }]
201 | }
202 | },
203 |
204 | // By default, your `index.html`'s will take care of
205 | // minification. These next options are pre-configured if you do not wish
206 | // to use the Usemin blocks.
207 | // cssmin: {
208 | // dist: {
209 | // files: {
210 | // '<%= config.dist %>/styles/main.css': [
211 | // '<%= config.app %>/styles/{,*/}*.css'
212 | // ]
213 | // }
214 | // }
215 | // },
216 | // uglify: {
217 | // dist: {
218 | // files: {
219 | // '<%= config.dist %>/scripts/scripts.js': [
220 | // '<%= config.dist %>/scripts/scripts.js'
221 | // ]
222 | // }
223 | // }
224 | // },
225 | // concat: {
226 | // dist: {}
227 | // },
228 |
229 | // Copies remaining files to places other tasks can use
230 | copy: {
231 | dist: {
232 | files: [{
233 | expand: true,
234 | dot: true,
235 | cwd: '<%= config.app %>',
236 | dest: '<%= config.dist %>',
237 | src: [
238 | '*.{ico,png,txt}',
239 | 'images/{,*/}*.{webp,gif}',
240 | '{,*/}*.html',
241 | '{,*/}*.js',
242 | 'styles/{,*/}*.css',
243 | 'styles/fonts/{,*/}*.*',
244 | '_locales/{,*/}*.json',
245 | ]
246 | }]
247 | }
248 | },
249 |
250 | // Run some tasks in parallel to speed up build process
251 | concurrent: {
252 | chrome: [
253 | ],
254 | dist: [
255 | 'imagemin',
256 | 'svgmin'
257 | ],
258 | test: [
259 | ]
260 | },
261 |
262 | // Auto buildnumber, exclude debug files. smart builds that event pages
263 | chromeManifest: {
264 | dist: {
265 | options: {
266 | buildnumber: true,
267 | background: {
268 | target: 'scripts/background.js',
269 | exclude: [
270 | 'scripts/chromereload.js'
271 | ]
272 | }
273 | },
274 | src: '<%= config.app %>',
275 | dest: '<%= config.dist %>'
276 | }
277 | },
278 |
279 | // Compres dist files to package
280 | compress: {
281 | dist: {
282 | options: {
283 | archive: function() {
284 | var manifest = grunt.file.readJSON('app/manifest.json');
285 | return 'package/Chrome Tab Search-' + manifest.version + '.zip';
286 | }
287 | },
288 | files: [{
289 | expand: true,
290 | cwd: 'dist/',
291 | src: ['**'],
292 | dest: ''
293 | }]
294 | }
295 | }
296 | });
297 |
298 | grunt.registerTask('debug', function () {
299 | grunt.task.run([
300 | 'concurrent:chrome',
301 | 'connect:chrome',
302 | 'watch'
303 | ]);
304 | });
305 |
306 | grunt.registerTask('test', [
307 | 'connect:test',
308 | 'mocha'
309 | ]);
310 |
311 | grunt.registerTask('build', [
312 | 'clean:dist',
313 | 'chromeManifest:dist',
314 | 'useminPrepare',
315 | 'concurrent:dist',
316 | // 'cssmin',
317 | 'concat',
318 | 'uglify',
319 | 'copy',
320 | 'usemin',
321 | 'compress'
322 | ]);
323 |
324 | grunt.registerTask('default', [
325 | 'test',
326 | 'build'
327 | ]);
328 | };
329 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Tablight
2 | ===============
3 |
4 | 
5 |
6 | Mac Spotlight search for Chrome tabs
7 |
8 | [Website](https://fouad.co/tablight)
9 |
--------------------------------------------------------------------------------
/app/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": {
3 | "message": "Tablight",
4 | "description": "The name of the application"
5 | },
6 | "appDescription": {
7 | "message": "Hot key (Cmd/Ctrl + O) that pulls up spotlight-like interface for open tabs.",
8 | "description": "The description of the application"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/images/icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/app/images/icon-128.png
--------------------------------------------------------------------------------
/app/images/icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/app/images/icon-16.png
--------------------------------------------------------------------------------
/app/images/icon-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/app/images/icon-48.png
--------------------------------------------------------------------------------
/app/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "__MSG_appName__",
3 | "version": "0.0.7",
4 | "manifest_version": 2,
5 | "description": "__MSG_appDescription__",
6 | "icons": {
7 | "16": "images/icon-16.png",
8 | "48": "images/icon-48.png",
9 | "128": "images/icon-128.png"
10 | },
11 | "default_locale": "en",
12 | "background": {
13 | "scripts": [
14 | "scripts/chromereload.js",
15 | "scripts/background.js"
16 | ]
17 | },
18 | "commands": {
19 | "open-search": {
20 | "description": "open search",
21 | "global": false,
22 | "suggested_key": {
23 | "default": "Ctrl+Shift+O",
24 | "mac": "Command+Shift+O"
25 | }
26 | }
27 | },
28 | "content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'",
29 | "permissions": [
30 | "tabs",
31 | "activeTab"
32 | ]
33 | }
--------------------------------------------------------------------------------
/app/pages/notice.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Tablight
9 | v
10 |
11 |
12 |
13 |
New update!
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/pages/permission.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Tablight
9 | v
10 |
11 |
12 |
13 |
Thanks for Installing!
14 |
15 | Press to search (Change the shortcut )
16 |
17 |
18 | I'd like to know how many people find this extension useful and which
19 | features actually help. All data collected is anonymized and does not
20 | contain any info about the tabs you're on.
21 |
22 |
Is it OK to share usage metrics with this developer?
23 |
No Thanks
24 |
Sure
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/scripts/background.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | console.log('Tab Search starting!');
4 | var _gaq = _gaq || [];
5 | var _tracking = false;
6 |
7 | chrome.runtime.onInstalled.addListener(function(details){
8 | if(details.reason == "install"){
9 | var permissionUrl = chrome.extension.getURL('pages/permission.html');
10 |
11 | chrome.tabs.create({url: permissionUrl});
12 | }else if(details.reason == "update"){
13 | var thisVersion = chrome.runtime.getManifest().version;
14 | console.log("Updated from " + details.previousVersion + " to " + thisVersion + "!");
15 | var noticeUrl = chrome.extension.getURL('pages/permission.html');
16 |
17 | chrome.tabs.create({url: noticeUrl});
18 | }
19 | });
20 |
21 | chrome.commands.onCommand.addListener(function(command) {
22 | var contentScript = chrome.extension.getURL('scripts/contentscript.js');
23 | var contentStyle = chrome.extension.getURL('styles/main.css');
24 |
25 | chrome.tabs.query({active: true}, function(tabs) {
26 | var currentTab = tabs[0];
27 | console.log(contentScript);
28 |
29 | chrome.tabs.executeScript({file: 'scripts/contentscript.js'}, function() {
30 | var port = chrome.tabs.connect(currentTab.id);
31 |
32 | chrome.tabs.query({active: false}, function(tabs) {
33 | port.postMessage({tabs: tabs});
34 | port.onMessage.addListener(handleSpotlight.bind(port));
35 | });
36 | });
37 | chrome.tabs.insertCSS({file: 'styles/main.css'});
38 | });
39 | });
40 |
41 | function setupTracking() {
42 | if (!_tracking) {
43 | return;
44 | }
45 |
46 | _gaq.push(['_setAccount', 'UA-58195300-1']);
47 | _gaq.push(['_trackPageview']);
48 |
49 | (function() {
50 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
51 | ga.src = 'https://ssl.google-analytics.com/ga.js';
52 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
53 | })();
54 | }
55 |
56 | var actions = {
57 | facebook: {
58 |
59 | }
60 | };
61 |
62 | function lookup(type) {
63 | actions[type];
64 | }
65 |
66 | function handleSpotlight(request) {
67 | var port = this;
68 |
69 | if (request.hasOwnProperty('query')) {
70 | var query = request.query.trim();
71 |
72 | if (query.indexOf('fb ') === 0) {
73 |
74 | chrome.tabs.query({url: '*://www.facebook.com/*'}, function(tabs) {
75 | if (tabs.length < 1) {
76 | chrome.tabs.create({
77 | url: 'https://www.facebook.com',
78 | active: false
79 | }, function() {
80 | lookup('facebook');
81 | });
82 | } else {
83 | lookup('facebook');
84 | }
85 | });
86 | }
87 | // chrome.tabs.query({active: false}, function(tabs) {
88 | // chrome.tabs.sendMessage(port.sender.tab.id, {tabs: tabs});
89 | // });
90 | } else if (request.hasOwnProperty('activate')) {
91 | if (_tracking) {
92 | _gaq.push(['_trackEvent', 'Background', 'Activate']);
93 | }
94 |
95 | chrome.tabs.update(request.activate, {active: true});
96 | } else if (request.hasOwnProperty('version')) {
97 | chrome.commands.getAll(function(commands) {
98 | port.postMessage({
99 | version: chrome.runtime.getManifest().version,
100 | command: commands[0]
101 | });
102 | });
103 | } else if (request.hasOwnProperty('analytics')) {
104 | _tracking = true;
105 | setupTracking();
106 | chrome.tabs.remove(port.sender.tab.id);
107 | }
108 | }
109 |
110 | chrome.runtime.onConnect.addListener(function(port) {
111 | port.onMessage.addListener(handleSpotlight.bind(port));
112 | });
113 |
--------------------------------------------------------------------------------
/app/scripts/chromereload.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Reload client for Chrome Apps & Extensions.
4 | // The reload client has a compatibility with livereload.
5 | // WARNING: only supports reload command.
6 |
7 | var LIVERELOAD_HOST = 'localhost:';
8 | var LIVERELOAD_PORT = 35729;
9 | var connection = new WebSocket('ws://' + LIVERELOAD_HOST + LIVERELOAD_PORT + '/livereload');
10 |
11 | connection.onerror = function (error) {
12 | console.log('reload connection got error' + JSON.stringify(error));
13 | };
14 |
15 | connection.onmessage = function (e) {
16 | if (e.data) {
17 | var data = JSON.parse(e.data);
18 | if (data && data.command === 'reload') {
19 | chrome.runtime.reload();
20 | }
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/app/scripts/contentscript.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var holder, tabList, _port, _cursor;
4 | var opened = false;
5 | var _tabs = [];
6 |
7 | function _listTab(tab) {
8 | var item = document.createElement('div');
9 | item.classList.add('tab-item');
10 |
11 | var title = document.createElement('h2');
12 | title.classList.add('tab--title');
13 | title.innerText = tab.title;
14 |
15 | var link = document.createElement('p');
16 | link.classList.add('tab--link');
17 | link.innerText = tab.url;
18 |
19 | item.appendChild(title);
20 | item.appendChild(link);
21 | item.tabId = tab.id;
22 |
23 | function navigateTab() {
24 | _closeSearch();
25 | _port.postMessage({activate: item.tabId});
26 | }
27 |
28 | item.addEventListener('click', navigateTab);
29 | item.navigate = navigateTab;
30 |
31 | tabList.appendChild(item);
32 | }
33 |
34 | function _openSearch(port) {
35 | console.log(port);
36 | _port = port;
37 | opened = true;
38 | holder = document.createElement('div');
39 | holder.classList.add('tab-search');
40 | tabList = document.createElement('div');
41 | tabList.classList.add('tab-list');
42 |
43 | setTimeout(function() {
44 | holder.classList.add('fadeIn');
45 | }, 0);
46 |
47 | var input = document.createElement('input');
48 |
49 | input.placeholder = 'Tab Search';
50 |
51 | holder.appendChild(input);
52 | holder.appendChild(tabList);
53 | document.body.appendChild(holder);
54 |
55 | input.focus();
56 |
57 | input.addEventListener('click', function(e) {
58 | e.stopPropagation();
59 | }, false);
60 | document.addEventListener('keydown', function(e) {
61 | if (e.keyCode === 27) {
62 | return _closeSearch();
63 | }
64 | });
65 | input.addEventListener('keydown', function(e) {
66 | var val = input.value.trim();
67 |
68 | // por
69 |
70 | if (e.keyCode === 38) {
71 |
72 | } else if (e.keyCode === 40) {
73 |
74 | } else if (e.keyCode === 27) {
75 | return _closeSearch();
76 | } else if (e.keyCode === 8 && val.length === 0) {
77 | return _closeSearch();
78 | } else if (e.keyCode === 13 && val.length > 0) {
79 | var tabs = _tabs.filter(function(tab) {
80 | return tab.url.indexOf(val) >= 0 || tab.title.trim().toLowerCase().indexOf(val) >= 0;
81 | });
82 |
83 | if (tabs.length > 0) {
84 | tabList.firstChild.navigate();
85 | }
86 | }
87 | });
88 |
89 | input.addEventListener('keyup', function() {
90 | var val = input.value.trim().toLowerCase();
91 |
92 | _port.postMessage({query: val});
93 |
94 | while (tabList.firstChild) {
95 | tabList.removeChild(tabList.firstChild);
96 | }
97 |
98 | if (val.length === 0) {
99 | return;
100 | }
101 |
102 | _cursor = null;
103 |
104 | var tabs = _tabs.filter(function(tab) {
105 | return tab.url.indexOf(val) >= 0 || tab.title.trim().toLowerCase().indexOf(val) >= 0;
106 | });
107 |
108 | tabs.map(_listTab);
109 | });
110 | }
111 |
112 | function _closeSearch() {
113 | opened = false;
114 |
115 | if (holder) {
116 | holder.classList.remove('fadeIn');
117 | }
118 | setTimeout(function() {
119 | if (holder) {
120 | holder.parentNode.removeChild(holder);
121 | }
122 |
123 | holder = null;
124 | tabList = null;
125 | _port = null;
126 | }, 250);
127 | }
128 |
129 | function _listenBack() {
130 | _closeSearch();
131 | document.removeEventListener('click', _listenBack);
132 | }
133 |
134 | function _listen() {
135 | document.addEventListener('keydown', function handleKeyup(e) {
136 | if ((e.ctrlKey || e.metaKey) && e.keyCode === 79) {
137 | e.preventDefault();
138 |
139 | if (!opened) {
140 | _openSearch();
141 | document.addEventListener('click', _listenBack);
142 | }
143 |
144 | return false;
145 | }
146 | }, false);
147 | }
148 |
149 | function loadTabs(response) {
150 | _tabs = response.tabs;
151 | }
152 |
153 | function TabSearch() {
154 | chrome.runtime.onConnect.addListener(function(port) {
155 | port.onMessage.addListener(function(msg) {
156 | if (msg.hasOwnProperty('tabs')) {
157 | loadTabs(msg);
158 |
159 | if (!opened) {
160 | _openSearch(port);
161 | document.addEventListener('click', _listenBack);
162 | }
163 | }
164 | });
165 | });
166 |
167 | // port = chrome.runtime.connect({name: 'tab-search'});
168 |
169 | // port.postMessage({query: ''});
170 | // port.onMessage.addListener(loadTabs);
171 | // chrome.runtime.onMessage.addListener(loadTabs);
172 | }
173 |
174 | // _listen();
175 | TabSearch();
176 |
--------------------------------------------------------------------------------
/app/scripts/notice.js:
--------------------------------------------------------------------------------
1 | var port = chrome.runtime.connect({name: "tablight"});
2 | var vspan = document.querySelector('.version');
3 | var osCut = document.querySelector('.os');
4 |
5 | port.onMessage.addListener(function(msg) {
6 | vspan.innerText = msg.version;
7 | osCut.innerText = msg.command.shortcut;
8 | console.log(msg.command);
9 | });
10 | port.postMessage({
11 | version: true
12 | });
13 |
14 | var decline = document.querySelector('.analytics-decline');
15 | var accept = document.querySelector('.analytics-accept');
16 | var configure = document.querySelector('.configure');
17 |
18 | decline.addEventListener('click', function() {
19 | window.close();
20 | });
21 |
22 | configure.addEventListener('click', function() {
23 | chrome.tabs.create({url: 'chrome://extensions/configureCommands'});
24 | });
25 |
26 | accept.addEventListener('click', function() {
27 | port.postMessage({
28 | analytics: true
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/app/styles/background.css:
--------------------------------------------------------------------------------
1 | body {
2 | /*background: #f8f8f8;*/
3 | background: #cbd9e0;
4 | -webkit-font-smoothing: antialiased;
5 | }
6 | h1, h2, h3, h4, p {
7 | font-weight: 400;
8 | font-family: 'Open Sans';
9 | /*-webkit-font-smoothing: antialiased;*/
10 | }
11 | header {
12 | padding: 20px 0;
13 | }
14 | header,
15 | .container {
16 | text-align: center;
17 | color: rgba(55,55,55,.85);
18 | }
19 | h4 {
20 | font-weight: bold;
21 | }
22 | .container p {
23 | max-width: 500px;
24 | margin: 15px auto;
25 | font-size: 16px;
26 | }
27 | .container button {
28 | margin: 15px 3px;
29 | padding: 8px 16px;
30 | font-size: 16px;
31 | background: none;
32 | color: rgba(100,100,100,.85);
33 | border: 2px solid;
34 | border-radius: 4px;
35 | cursor: pointer;
36 | transition: background .35s ease-out;
37 | outline: none;
38 | }
39 |
40 | .container button:hover {
41 | background: rgba(100,100,100,.1);
42 | }
43 |
44 | .container button:active {
45 | background: rgba(0,0,0,.1);
46 | }
47 | .container button.analytics-accept {
48 | color: white;
49 | background: rgba(68, 138, 255, 1);
50 | border-color: rgba(68, 138, 255, 1);
51 | }
52 | .container button.analytics-accept:hover {
53 | color: white;
54 | background: rgba(68, 138, 255, .85);
55 | border-color: rgba(68, 138, 255, .85);
56 | }
57 | .container button.analytics-accept {
58 | color: white;
59 | background: rgba(68, 138, 255, 1);
60 | border-color: rgba(68, 138, 255, 1);
61 | }
62 |
--------------------------------------------------------------------------------
/app/styles/main.css:
--------------------------------------------------------------------------------
1 | .tab-search,
2 | .tab-search input,
3 | .tab-list {
4 | box-sizing: border-box;
5 | }
6 | .tab-search {
7 | position: fixed;
8 | top: 30%;
9 | width: 70%;
10 | height: 70px;
11 | margin-left: 15%;
12 | opacity: 0;
13 | z-index: 5000;
14 | transform: translateY(20px) scale(.85);
15 | transition: all .25s ease-out;
16 | }
17 | .tab-search.fadeIn {
18 | opacity: 1;
19 | transform: translateY(0) scale(.9999);
20 | }
21 | .tab-search input,
22 | .tab-search input:focus {
23 | position: relative;
24 | width: 100%;
25 | height: 100%;
26 | margin: 0;
27 | padding: 8px 16px;
28 | font-size: 38px;
29 | line-height: normal;
30 | background: rgba(255,255,255,.96);
31 | border: none;
32 | border-radius: 4px;
33 | z-index: 300;
34 | box-shadow: 0 5px 30px rgba(50,50,50,.85);
35 | }
36 | .tab-search input:focus {
37 | outline: none;
38 | }
39 | .tab-list {
40 | max-height: 400px;
41 | overflow-y: scroll;
42 | padding-top: 15px;
43 | }
44 | .tab-item {
45 | width: 90%;
46 | margin: 0 auto 15px;
47 | padding: 10px 20px;
48 | background: white;
49 | border-radius: 4px;
50 | text-align: left;
51 | /*box-shadow: 0 2px 6px rgba(0,0,0,.35);*/
52 | box-shadow: 0 2px 10px rgba(50,50,50,.45);
53 | cursor: pointer;
54 | transition: background .45s ease-out;
55 | }
56 | .tab-item:hover {
57 | background: #CFD8DC;
58 | }
59 | .tab--title {
60 | margin: 15px 0 0;
61 | font-weight: 400;
62 | font-size: 22px;
63 | line-height: normal;
64 | color: #455A64;
65 | transition: color .15s ease-out;
66 | }
67 | .tab-item:hover .tab--title {
68 | color: #37474F;
69 | }
70 | .tab--link {
71 | margin: 8px 0;
72 | font-size: 14px;
73 | line-height: 18px;
74 | color: #78909C;
75 | }
76 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chrome-tab-search",
3 | "version": "0.0.0",
4 | "dependencies": {},
5 | "devDependencies": {}
6 | }
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chrome-tab-search",
3 | "version": "0.0.1",
4 | "dependencies": {},
5 | "devDependencies": {
6 | "grunt": "~0.4.1",
7 | "grunt-contrib-copy": "~0.5.0",
8 | "grunt-contrib-concat": "~0.3.0",
9 | "grunt-contrib-uglify": "~0.4.0",
10 | "grunt-contrib-jshint": "~0.9.2",
11 | "grunt-contrib-cssmin": "~0.9.0",
12 | "grunt-contrib-connect": "~0.7.1",
13 | "grunt-contrib-clean": "~0.5.0",
14 | "grunt-contrib-htmlmin": "~0.2.0",
15 | "grunt-bower-install": "~1.0.0",
16 | "grunt-contrib-imagemin": "~0.7.1",
17 | "grunt-contrib-watch": "~0.6.1",
18 | "grunt-usemin": "~2.1.0",
19 | "grunt-mocha": "~0.4.10",
20 | "grunt-svgmin": "~0.4.0",
21 | "grunt-concurrent": "~0.5.0",
22 | "load-grunt-tasks": "~0.4.0",
23 | "time-grunt": "~0.3.1",
24 | "jshint-stylish": "~0.1.5",
25 | "grunt-chrome-manifest": "~0.2.0",
26 | "grunt-contrib-compress": "~0.9.1"
27 | },
28 | "engines": {
29 | "node": ">=0.8.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/promo/large-tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/promo/large-tile.png
--------------------------------------------------------------------------------
/promo/marquee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/promo/marquee.png
--------------------------------------------------------------------------------
/promo/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/promo/screenshot.png
--------------------------------------------------------------------------------
/promo/small-tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fouad/chrome-tablight/93221f601fb72ef3f6af4e22fda1b688fe634cec/promo/small-tile.png
--------------------------------------------------------------------------------
/test/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/test/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tab-search",
3 | "private": true,
4 | "dependencies": {
5 | "chai": "~1.8.0",
6 | "mocha": "~1.14.0"
7 | },
8 | "devDependencies": {}
9 | }
10 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Mocha Spec Runner
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/spec/test.js:
--------------------------------------------------------------------------------
1 | /* global describe, it */
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | describe('Give it some context', function () {
7 | describe('maybe a bit more context here', function () {
8 | it('should run here few assertions', function () {
9 |
10 | });
11 | });
12 | });
13 | })();
14 |
--------------------------------------------------------------------------------