├── .babelrc.js
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .nvmrc
├── .travis.yml
├── LICENSE
├── README.md
├── app
├── about.js
├── app.html
├── app.js
├── assets
│ ├── images
│ │ ├── iconTemplate.png
│ │ └── iconTemplate@2x.png
│ ├── stylesheets
│ │ ├── debug.css
│ │ └── font-awesome.min.css
│ └── webfonts
│ │ ├── fa-brands-400.eot
│ │ ├── fa-brands-400.svg
│ │ ├── fa-brands-400.ttf
│ │ ├── fa-brands-400.woff
│ │ ├── fa-brands-400.woff2
│ │ ├── fa-regular-400.eot
│ │ ├── fa-regular-400.svg
│ │ ├── fa-regular-400.ttf
│ │ ├── fa-regular-400.woff
│ │ ├── fa-regular-400.woff2
│ │ ├── fa-solid-900.eot
│ │ ├── fa-solid-900.svg
│ │ ├── fa-solid-900.ttf
│ │ ├── fa-solid-900.woff
│ │ └── fa-solid-900.woff2
├── background.js
├── blocks
│ ├── block.js
│ ├── external.js
│ ├── external
│ │ ├── hotkey.js
│ │ └── serviceScript.js
│ ├── externalBlock.js
│ ├── input.js
│ ├── input
│ │ ├── keyword.js
│ │ ├── prefixScript.js
│ │ └── rootScript.js
│ ├── inputBlock.js
│ ├── output.js
│ └── output
│ │ ├── copyToClipboard.js
│ │ ├── openFile.js
│ │ ├── openInBrowser.js
│ │ ├── playSound.js
│ │ ├── preview.js
│ │ ├── reloadConfig.js
│ │ ├── sendNotification.js
│ │ ├── showFile.js
│ │ └── userScript.js
├── components
│ ├── debug.js
│ ├── loadingSpinner.js
│ ├── noplugins.js
│ ├── result.js
│ ├── results.js
│ ├── search.js
│ └── style.js
├── containers
│ ├── configWrapper.js
│ ├── databaseWrapper.js
│ ├── pluginWrapper.js
│ └── zazu.js
├── debug.html
├── debug.js
├── helpers
│ ├── menu.js
│ ├── singleInstance.js
│ ├── startup.js
│ └── window.js
├── lib
│ ├── configuration.js
│ ├── download.js
│ ├── env.js
│ ├── git.js
│ ├── github.js
│ ├── globalEmitter.js
│ ├── installStatus.js
│ ├── json.js
│ ├── keyboard.js
│ ├── logger.js
│ ├── manager.js
│ ├── mergeUnique.js
│ ├── notification.js
│ ├── npmInstall.js
│ ├── pluginFreshRequire.js
│ ├── pluginTransport.js
│ ├── retry.js
│ ├── screens.js
│ ├── template.js
│ ├── track.js
│ ├── track
│ │ ├── newrelic.js
│ │ └── noop.js
│ ├── truncateResult.js
│ └── update.js
├── packages
│ ├── package.js
│ ├── plugin.js
│ └── theme.js
├── preview.html
├── registBabel.js
├── templates
│ └── zazurc.json
└── transforms
│ └── resultSorter.js
├── appveyor.yml
├── changelog.md
├── code_of_conduct.md
├── configs
├── webpack.config.base.js
├── webpack.config.main.prod.babel.js
├── webpack.config.renderer.debug.prod.babel.js
└── webpack.config.renderer.prod.babel.js
├── docs
├── .gitignore
├── .ruby-version
├── .spelling
├── .travis.yml
├── 404.md
├── CNAME
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── _config.yml
├── _documentation
│ ├── blocks.md
│ ├── configuration.md
│ ├── getting-started.md
│ ├── plugins.md
│ └── themes.md
├── _includes
│ ├── feedback.html
│ ├── footer.html
│ ├── fork.html
│ ├── head.html
│ ├── navigation.html
│ ├── social.html
│ └── underbar.html
├── _layouts
│ ├── default.html
│ ├── documentation.html
│ ├── page.html
│ └── sidebar-page.html
├── _packages
│ ├── another-dark-theme.md
│ ├── ascii-search.md
│ ├── battery.md
│ ├── calculator.md
│ ├── caniuse.md
│ ├── capybara-theme.md
│ ├── chrome-bookmarks.md
│ ├── clean-dark-theme.md
│ ├── clement-theme.md
│ ├── clipboard.md
│ ├── colors.md
│ ├── currency-convertor.md
│ ├── dark-solarized.md
│ ├── dark-theme.md
│ ├── dash.md
│ ├── dev-doc.md
│ ├── devdocs.md
│ ├── dictionary.md
│ ├── docker.md
│ ├── emoj.md
│ ├── emoji.md
│ ├── encode-decode.md
│ ├── fallback.md
│ ├── file-finder.md
│ ├── firefox-bookmarks.md
│ ├── fkill.md
│ ├── free-shadowsocks.md
│ ├── giphy.md
│ ├── gist.md
│ ├── github-repos.md
│ ├── github.md
│ ├── hacker-news.md
│ ├── hash.md
│ ├── homebrew.md
│ ├── ip-address.md
│ ├── js-beautify.md
│ ├── light-solarized.md
│ ├── light-theme.md
│ ├── mac-1password.md
│ ├── mac-open-terminal.md
│ ├── mac-vpn.md
│ ├── npms.md
│ ├── omnifocus.md
│ ├── package-manager.md
│ ├── packagist.md
│ ├── password.md
│ ├── pibble.md
│ ├── placehold.it.md
│ ├── playful-theme.md
│ ├── pypi.md
│ ├── rubygems.md
│ ├── simple-theme.md
│ ├── snippets.md
│ ├── system.md
│ ├── timetracker.md
│ ├── timezone.md
│ ├── tldr.md
│ ├── translation-and-optional-anki.md
│ ├── uptime.md
│ ├── utime.md
│ └── weather.md
├── _pages
│ ├── documentation.html
│ ├── download.html
│ ├── faq.html
│ ├── plugins.html
│ └── themes.html
├── _posts
│ ├── 2017-03-07-video-introduction-to-zazu.md
│ └── 2017-03-18-zazu-v0.5.0.md
├── _sass
│ ├── base
│ │ └── _reset.scss
│ ├── components
│ │ ├── _archives.scss
│ │ ├── _article.scss
│ │ ├── _buttons.scss
│ │ ├── _feedback.scss
│ │ ├── _footer.scss
│ │ ├── _fork.scss
│ │ ├── _header.scss
│ │ ├── _navigation.scss
│ │ ├── _packages.scss
│ │ ├── _search.scss
│ │ ├── _social.scss
│ │ └── _underbar.scss
│ ├── helpers
│ │ ├── _mixins.scss
│ │ └── _variables.scss
│ ├── themes
│ │ ├── _blue.scss
│ │ ├── _green.scss
│ │ ├── _grey.scss
│ │ ├── _mint.scss
│ │ ├── _orange.scss
│ │ ├── _purple.scss
│ │ └── _teal.scss
│ ├── utilities
│ │ ├── _layout.scss
│ │ └── _themes.scss
│ └── vendor
│ │ └── _syntax-highlighting.scss
├── api
│ ├── docs.json
│ ├── packages.json
│ ├── posts.json
│ └── version.json
├── blog
│ └── index.html
├── css
│ └── main.scss
├── favicon.ico
├── feed.xml
├── images
│ ├── action-shots
│ │ ├── calculator.png
│ │ ├── clipboard.png
│ │ ├── file-finder.png
│ │ ├── package-manager.png
│ │ ├── system.png
│ │ └── video.png
│ ├── os-icons
│ │ ├── mac.png
│ │ ├── ubuntu.png
│ │ └── windows.png
│ └── package-icons
│ │ ├── 1password.png
│ │ ├── another-dark-theme.png
│ │ ├── ascii-search.png
│ │ ├── battery.png
│ │ ├── calculator.png
│ │ ├── caniuse.png
│ │ ├── capybara-theme.png
│ │ ├── chrome.png
│ │ ├── clean-dark-theme.png
│ │ ├── clement-theme.png
│ │ ├── clipboard.png
│ │ ├── colors.png
│ │ ├── currency-convertor.svg
│ │ ├── dark-solarized-theme.png
│ │ ├── dark-theme.png
│ │ ├── dash.png
│ │ ├── devdocs.png
│ │ ├── dictionary.png
│ │ ├── docker.png
│ │ ├── emoj.svg
│ │ ├── encode-decode.svg
│ │ ├── fallback.png
│ │ ├── file-finder.png
│ │ ├── firefox.png
│ │ ├── fkill.png
│ │ ├── free-shadowsocks.png
│ │ ├── giphy.png
│ │ ├── github-repos.png
│ │ ├── github.png
│ │ ├── hacker-news.png
│ │ ├── hash.svg
│ │ ├── homebrew.png
│ │ ├── ip-address.svg
│ │ ├── js-beautify.png
│ │ ├── light-theme.png
│ │ ├── npms.png
│ │ ├── omnifocus.png
│ │ ├── package-manager.png
│ │ ├── packagist.png
│ │ ├── password.png
│ │ ├── pibble.png
│ │ ├── placehold.png
│ │ ├── playful-theme.png
│ │ ├── pypi.png
│ │ ├── rubygems.png
│ │ ├── simple-theme.png
│ │ ├── snippets.svg
│ │ ├── system.png
│ │ ├── terminal.png
│ │ ├── timetracker.svg
│ │ ├── timezone.svg
│ │ ├── tldr.png
│ │ ├── translation.png
│ │ ├── uptime.png
│ │ ├── vpn.png
│ │ ├── weather.png
│ │ ├── zazu-dev-doc.png
│ │ └── zazu-emoji.png
├── index.html
├── js
│ ├── feedback.js
│ ├── headers.js
│ ├── search.js
│ ├── triangle-header.js
│ └── vendor
│ │ ├── fetch.min.js
│ │ ├── fuzzyfind.min.js
│ │ └── trianglify.min.js
└── robots.txt
├── features
├── accessibility.feature
├── input_blocks.feature
├── installing_plugins.feature
├── navigate_results.feature
├── open.feature
├── output_blocks.feature
├── step_definitions
│ └── myStepDefinitions.js
├── support
│ ├── after_hooks.js
│ └── custom_formattor.js
└── updating_plugins.feature
├── gulpfile.js
├── package-lock.json
├── package.json
├── resources
├── icons
│ └── 512x512.png
├── osx
│ ├── dmg-background.png
│ ├── dmg-background@2x.png
│ ├── dmg-icon.icns
│ └── icon.icns
└── windows
│ ├── icon.ico
│ └── setup-icon.ico
├── tasks
└── ghpages.js
└── test
├── .eslintrc
├── app
├── blocks
│ ├── external
│ │ └── service.spec.js
│ ├── input
│ │ ├── prefixScript.spec.js
│ │ └── rootScript.spec.js
│ └── output
│ │ └── userScript.spec.js
├── lib
│ ├── configuration.spec.js
│ ├── manager.spec.js
│ ├── mergeUnique.spec.js
│ ├── notification.spec.js
│ └── template.spec.js
├── packages
│ └── plugin.spec.js
└── transforms
│ └── resultSorter.spec.js
└── fixtures
└── home
├── .calculator.zazurc.json
├── .fallback.zazurc.json
├── .zazu
├── databases
│ └── installStatus.nedb
└── plugins
│ └── tinytacoteam
│ └── zazu-fixture
│ ├── copyPasta.js
│ ├── food.js
│ ├── main.css
│ ├── process.js
│ └── zazu.json
└── .zazurc.json
/.babelrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ignore: [/\/(node_modules)\//, /newrelic\.js/],
3 | presets: [
4 | [
5 | '@babel/preset-env',
6 | {
7 | targets: {
8 | electron: '5',
9 | },
10 | },
11 | ],
12 | '@babel/preset-react',
13 | ],
14 | plugins: [
15 | 'babel-plugin-macros',
16 | '@babel/plugin-syntax-dynamic-import',
17 | 'dynamic-import-node-babel-7',
18 | '@babel/plugin-proposal-class-properties',
19 | '@babel/plugin-transform-react-constant-elements',
20 | '@babel/plugin-transform-react-inline-elements',
21 | 'babel-plugin-closure-elimination',
22 | ],
23 | }
24 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | insert_final_newline = true
6 |
7 | [*.js]
8 | indent_style = space
9 | indent_size = 2
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | vendor
3 | build
4 | resources
5 | plugins
6 | docs
7 | dist
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: 'babel-eslint',
3 | extends: ['standard', 'plugin:react/recommended'],
4 | rules: { 'comma-dangle': [2, 'always-multiline'] },
5 | plugins: ['react', 'html'],
6 | parserOptions: {
7 | ecmaFeatures: {
8 | jsx: true,
9 | },
10 | },
11 | settings: {
12 | react: {
13 | version: '16.8.6',
14 | },
15 | },
16 | globals: {
17 | newrelic: true,
18 | __nr_require: true,
19 | },
20 | env: {
21 | browser: true,
22 | node: true,
23 | es6: true,
24 | mocha: true,
25 | node: true,
26 | },
27 | }
28 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Getting Involved
2 |
3 | ### What's being worked on now
4 |
5 | The core team tracks what is currently being worked on on the [Zazu Project
6 | Board][Zazu Project Board].
7 |
8 | ### Zazu Core
9 |
10 | You can also look through currently open issues in Zazu Core. Often, the ones
11 | not being worked on are marked with a [help wanted][help wanted tag]. tag.
12 |
13 | ### Plugins
14 |
15 | Plugin development is also a great way to get involved. Zazu needs plugin to do
16 | anything useful for a user. If you create one, start the repo name with `zazu-`
17 | and feel free to submit it to the plugin directory once you get it working! If
18 | you need help getting started there is documentation on [creating a
19 | plugin][plugin page].
20 |
21 | ## Community
22 |
23 | You can find the community and core developers on [Gitter Chat][Gitter Chat].
24 |
25 | ## Core Team Guidelines
26 |
27 | If you're part of Zazu's core team there are a few guidelines for you as well.
28 |
29 | When starting work, please update the [Roadmap][Roadmap] with your current task.
30 | When you create a pull request, add a reviewer who is also on the core team. Add
31 | a label for which [semver][semver] number needs to be bumped, for example `major
32 | version`, `minor version` or `patch version`.
33 |
34 | If you get added as a reviewer and you don't have time to get to it in the next
35 | day or two, feel free to comment or re-assign the ticket, things come up, we
36 | understand! [:
37 |
38 | If there is no reviewer on a pull request, from a non-core member for example,
39 | assign it to yourself and take it from there.
40 |
41 | When making a review:
42 |
43 | * Verify semver label
44 | * Look at the code
45 | * Run code/docs locally
46 |
47 | Once approved of the change:
48 |
49 | * Merge the pull request
50 | * Publish the documentation if necessary (eg `npm run docs:publish`)
51 |
52 | [semver]: http://semver.org/
53 | [Roadmap]: https://github.com/tinytacoteam/zazu/projects/3
54 | [help wanted tag]: https://github.com/tinytacoteam/zazu/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
55 | [plugin page]: http://zazuapp.org/documentation/plugins/
56 | [Gitter Chat]: https://gitter.im/tinytacoteam/zazu
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Expected Behavior
2 |
3 | ### Actual Behavior
4 |
5 | ### Steps to reproduce the behavior
6 |
7 | ### Versions
8 |
9 | * Zazu:
10 | * OS:
11 | * GIT:
12 |
13 | Please, include a link to gist of most applicable `~/.zazu/log/` file.
14 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | All pull requests should go to `master`, even the documentation is in `master`
2 | under `./docs/`.
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | log
4 | .DS_Store
5 | Thumbs.db
6 | *.autogenerated
7 | build
8 | releases
9 | dist
10 | tmp
11 | docs/_site
12 | databases
13 | zazu-fallback
14 | zazu-calculator
15 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v9.8.0
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 'lts/*'
4 |
5 |
6 | matrix:
7 | fast_finish: true
8 | include:
9 | - os: osx
10 | osx_image: xcode9.4
11 | env:
12 | - ELECTRON_CACHE=$HOME/.cache/electron
13 | - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
14 |
15 | - os: linux
16 | services:
17 | - xvfb
18 |
19 | cache:
20 | directories:
21 | - $HOME/.cache/electron
22 | - $HOME/.cache/electron-builder
23 |
24 | script:
25 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then npm run cucumber; fi
26 | - npm test
27 | - |
28 | if [ "$TRAVIS_OS_NAME" == "linux" ]; then
29 | npm run release:linux;
30 | else
31 | npm run release:osx
32 | fi
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Tiny Taco Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/about.js:
--------------------------------------------------------------------------------
1 | const { app, clipboard, dialog } = require('electron')
2 | const env = require('./lib/env')
3 |
4 | const items = [
5 | { name: 'App Environment', value: env.name },
6 | { name: 'App Version', value: app.getVersion() },
7 | { name: 'Electron Version', value: process.versions.electron },
8 | { name: 'Node Version', value: process.versions.node },
9 | { name: 'Chrome Version', value: process.versions.chrome },
10 | ]
11 |
12 | module.exports = {
13 | show () {
14 | const detail = items.map((item) => {
15 | return item.name + ': ' + item.value
16 | }).join('\n')
17 | dialog.showMessageBox({
18 | type: 'info',
19 | message: 'Zazu App',
20 | detail,
21 | defaultId: 0,
22 | buttons: ['Ok', 'Copy'],
23 | }, (index) => {
24 | if (index === 1) {
25 | clipboard.writeText(detail)
26 | }
27 | })
28 | },
29 | }
30 |
--------------------------------------------------------------------------------
/app/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zazu
6 |
16 |
17 |
18 |
19 |
20 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/app.js:
--------------------------------------------------------------------------------
1 | const ReactDOM = require('react-dom')
2 | const React = require('react')
3 |
4 | const ConfigWrapper = require('./containers/configWrapper')
5 | const PluginWrapper = require('./containers/pluginWrapper')
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('zazu')
12 | )
13 |
14 | // Catch `esc` or `enter` to avoid alert beep.
15 | document.body.onkeydown = e => {
16 | return e.key !== 'Enter' && e.key !== 'Escape'
17 | }
18 |
--------------------------------------------------------------------------------
/app/assets/images/iconTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/images/iconTemplate.png
--------------------------------------------------------------------------------
/app/assets/images/iconTemplate@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/images/iconTemplate@2x.png
--------------------------------------------------------------------------------
/app/assets/stylesheets/debug.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #ECECEC;
3 | }
4 | section {
5 | width: 100%;
6 | height: 200px;
7 | text-align: center;
8 | font-family: 'Roboto', 'Helvetica Neue', Helvetica, sans-serif;
9 | }
10 | img {
11 | width: 75px;
12 | height: 75px;
13 | }
14 | h2 {
15 | margin-bottom: 0;
16 | }
17 | ul {
18 | margin: 0;
19 | padding: 0;
20 | }
21 | li {
22 | list-style: none;
23 | }
24 | pre.verbose {
25 | border-left: 5px solid #31708F;
26 | color: #31708F;
27 | padding-left: 5px;
28 | background-color: #D9EDF7;
29 | }
30 | pre.info {
31 | border-left: 5px solid #3C763D;
32 | color: #3C763D;
33 | padding-left: 5px;
34 | background-color: #DFF0D8;
35 | }
36 | pre.warn {
37 | border-left: 5px solid #8A6D3B;
38 | color: #8A6D3B;
39 | padding-left: 5px;
40 | background-color: #FCF8E3;
41 | }
42 | pre.error {
43 | border-left: 5px solid #A94442;
44 | color: #A94442;
45 | padding-left: 5px;
46 | background-color: #F2DEDE;
47 | }
48 |
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/app/assets/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bayleeadamoss/zazu/e6e37e63841ca4e8abd6bd6dfc7d211ae30d18d5/app/assets/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/app/blocks/block.js:
--------------------------------------------------------------------------------
1 | const cuid = require('cuid')
2 |
3 | const logger = require('../lib/logger')
4 |
5 | class Block {
6 | constructor (data) {
7 | this.pluginId = data.pluginId
8 | this.type = data.type
9 | this.id = data.id || cuid()
10 | this.connections = data.connections || []
11 | this.logger = logger.bindMeta({ plugin: this.pluginId, block: this.id })
12 | }
13 |
14 | requiredField (fieldName) {
15 | const blockName = this.constructor.name
16 | this.logger.log('error', `Field "${fieldName}" is required.`, {
17 | fieldName,
18 | blockName,
19 | })
20 | }
21 |
22 | _ensurePromise (val) {
23 | if (!(val instanceof Promise)) {
24 | this.logger.log('error', 'Block did not return a Promise')
25 | return Promise.resolve()
26 | }
27 | return val
28 | }
29 |
30 | call (state) {
31 | return state.next()
32 | }
33 | }
34 |
35 | module.exports = Block
36 |
--------------------------------------------------------------------------------
/app/blocks/external.js:
--------------------------------------------------------------------------------
1 | const Hotkey = require('./external/hotkey')
2 | const ServiceScript = require('./external/serviceScript')
3 |
4 | module.exports = {
5 | Hotkey,
6 | ServiceScript,
7 | }
8 |
--------------------------------------------------------------------------------
/app/blocks/external/hotkey.js:
--------------------------------------------------------------------------------
1 | const globalEmitter = require('../../lib/globalEmitter')
2 | const ExternalBlock = require('../externalBlock')
3 |
4 | class Hotkey extends ExternalBlock {
5 | constructor (data, options) {
6 | super(data, options)
7 | this.connections = data.connections || []
8 | this.hotkey = options[this.id] || data.hotkey
9 | }
10 |
11 | start () {
12 | globalEmitter.emit('registerHotkey', this.hotkey)
13 | globalEmitter.on('triggerHotkey', (accelerator) => {
14 | if (this.hotkey === accelerator) {
15 | this.logger.log('info', 'Hotkey triggered', { accelerator })
16 | this.handle()
17 | }
18 | })
19 | }
20 |
21 | handle () {
22 | this.emit('actioned')
23 | }
24 | }
25 |
26 | module.exports = Hotkey
27 |
--------------------------------------------------------------------------------
/app/blocks/external/serviceScript.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const electron = require('electron')
3 |
4 | const ExternalBlock = require('../externalBlock')
5 |
6 | class ServiceScript extends ExternalBlock {
7 | constructor (data, options) {
8 | super(data, options)
9 | this.cwd = data.cwd
10 | this.options = options
11 | this.type = data.type
12 | this.connections = []
13 | this.interval = parseInt(data.interval, 10)
14 | if (isNaN(this.interval) || this.interval < 100) {
15 | this.interval = 100
16 | }
17 | try {
18 | const plugin = electron.remote.require(path.join(this.cwd, data.script))
19 |
20 | this.script = plugin({
21 | console: this.logger,
22 | cwd: this.cwd,
23 | })
24 | } catch (e) {
25 | this.script = false
26 | this.loadError = e
27 | }
28 | }
29 |
30 | start () {
31 | return this.handle()
32 | }
33 |
34 | handle () {
35 | if (!this.script) {
36 | this.logger.error('Plugin failed to load', this.loadError)
37 | return Promise.resolve()
38 | }
39 | return this._ensurePromise(this.script(this.options))
40 | .then(() => new Promise((resolve) => {
41 | setTimeout(resolve, this.interval)
42 | }))
43 | .then(() => this.start())
44 | .catch((error) => {
45 | this.logger.error('Script failed', error)
46 | })
47 | }
48 | }
49 |
50 | module.exports = ServiceScript
51 |
--------------------------------------------------------------------------------
/app/blocks/externalBlock.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require('events')
2 | const cuid = require('cuid')
3 |
4 | const logger = require('../lib/logger')
5 |
6 | class ExternalBlock extends EventEmitter {
7 | constructor (data, options) {
8 | super()
9 | this.pluginId = data.pluginId
10 | this.id = data.id || cuid()
11 | this.logger = logger.bindMeta({ plugin: data.pluginId, block: this.id })
12 | }
13 |
14 | _ensurePromise (val) {
15 | if (!(val instanceof Promise)) {
16 | this.logger.log('error', 'Block did not return a Promise')
17 | return Promise.resolve()
18 | }
19 | return val
20 | }
21 |
22 | call () {
23 | return Promise.resolve()
24 | }
25 | }
26 |
27 | module.exports = ExternalBlock
28 |
--------------------------------------------------------------------------------
/app/blocks/input.js:
--------------------------------------------------------------------------------
1 | const RootScript = require('./input/rootScript')
2 | const PrefixScript = require('./input/prefixScript')
3 | const Keyword = require('./input/keyword')
4 |
5 | module.exports = {
6 | RootScript,
7 | PrefixScript,
8 | Keyword,
9 | }
10 |
--------------------------------------------------------------------------------
/app/blocks/input/keyword.js:
--------------------------------------------------------------------------------
1 | const InputBlock = require('../inputBlock')
2 |
3 | class Keyword extends InputBlock {
4 | constructor (data) {
5 | super(data)
6 | this.keyword = data.keyword || this.requiredField('keyword')
7 | this.title = data.title || this.requiredField('title')
8 | this.subtitle = data.subtitle
9 | this.icon = data.icon
10 | }
11 |
12 | respondsTo (input) {
13 | const longEnough = input.length > 2
14 | const partOfKeyword = this.keyword.indexOf(input) !== -1
15 | const respondsTo = longEnough && !!partOfKeyword
16 | this.logger.log('verbose', `${respondsTo ? 'r' : 'notR'}esponds to input`, { input, respondsTo })
17 | return respondsTo
18 | }
19 |
20 | search (input, env = {}) {
21 | this.logger.log('info', 'Rendering keyword', { input })
22 | return Promise.resolve([
23 | {
24 | blockRank: 2,
25 | title: this.title,
26 | subtitle: this.subtitle,
27 | value: this.keyword,
28 | icon: this.icon,
29 | },
30 | ])
31 | }
32 | }
33 |
34 | module.exports = Keyword
35 |
--------------------------------------------------------------------------------
/app/blocks/input/rootScript.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const electron = require('electron')
3 |
4 | const InputBlock = require('../inputBlock')
5 | const truncateResult = require('../../lib/truncateResult')
6 |
7 | class RootScript extends InputBlock {
8 | constructor (data) {
9 | super(data)
10 | try {
11 | const plugin = electron.remote.require(path.join(data.cwd, data.script))
12 | this.script = plugin({
13 | console: this.logger,
14 | cwd: data.cwd,
15 | })
16 | } catch (e) {
17 | this.script = false
18 | this.loadError = e
19 | }
20 | }
21 |
22 | respondsTo (input, env = {}) {
23 | if (!this.script) {
24 | this.logger.error('Plugin failed to load', this.loadError)
25 | return false
26 | }
27 | const respondsTo = !!this.script.respondsTo(input, env)
28 | this.logger.log('verbose', `${respondsTo ? 'r' : 'notR'}espondsTo`, { input, respondsTo })
29 | return respondsTo
30 | }
31 |
32 | query (input) {
33 | return input
34 | }
35 |
36 | search (input, env = {}) {
37 | const query = this.query(input)
38 | this.logger.log('verbose', 'Executing Script', { query })
39 | return new Promise((resolve, reject) => {
40 | const timeout = setTimeout(() => {
41 | timeout === this.timeout ? resolve() : reject(new Error('Debounced'))
42 | }, this.debounce)
43 | this.timeout = timeout
44 | }).then(() => {
45 | return this._ensurePromise(this.script.search(query, env))
46 | }).then((results) => {
47 | this.logger.log('info', 'Script Results', { results: (Array.isArray(results) ? results.map(truncateResult) : results) })
48 | return this._validateResults(results.map((result) => Object.assign({}, result, { blockRank: 1 })))
49 | }).catch((error) => {
50 | if (error.message === 'Debounced') {
51 | this.logger.log('verbose', error.message, { query, error })
52 | } else {
53 | this.logger.error('Script failed', { query, error })
54 | }
55 | })
56 | }
57 | }
58 |
59 | module.exports = RootScript
60 |
--------------------------------------------------------------------------------
/app/blocks/inputBlock.js:
--------------------------------------------------------------------------------
1 | const Block = require('./block')
2 |
3 | const globalEmitter = require('../lib/globalEmitter')
4 | const truncateResult = require('../lib/truncateResult')
5 |
6 | class InputBlock extends Block {
7 | constructor (data) {
8 | super(data)
9 | this.pluginId = data.pluginId
10 | this.isScoped = null
11 | this.debounce = data.debounce || 100
12 | }
13 |
14 | isActive () {
15 | return this.isScoped !== false
16 | }
17 |
18 | setScoped (value) {
19 | this.isScoped = value
20 | }
21 |
22 | _validateResults (results) {
23 | if (!Array.isArray(results)) {
24 | this.logger.log('error', 'results must be an array', {
25 | results,
26 | })
27 | return []
28 | }
29 | results.forEach((result) => {
30 | const keys = Object.keys(result)
31 | if (!keys.includes('title')) {
32 | this.logger.log('error', 'result must contain a title', { result: truncateResult(result) })
33 | }
34 | if (!keys.includes('value')) {
35 | this.logger.log('error', 'result must contain a value', { result: truncateResult(result) })
36 | }
37 | })
38 | return results
39 | }
40 |
41 | call (state) {
42 | setImmediate(() => {
43 | globalEmitter.emit('showWindow', this.pluginId, this.id)
44 | })
45 | return Promise.resolve()
46 | }
47 | }
48 |
49 | module.exports = InputBlock
50 |
--------------------------------------------------------------------------------
/app/blocks/output.js:
--------------------------------------------------------------------------------
1 | const CopyToClipboard = require('./output/copyToClipboard')
2 | const OpenInBrowser = require('./output/openInBrowser')
3 | const SendNotification = require('./output/sendNotification')
4 | const UserScript = require('./output/userScript')
5 | const ShowFile = require('./output/showFile')
6 | const OpenFile = require('./output/openFile')
7 | const ReloadConfig = require('./output/reloadConfig')
8 | const Preview = require('./output/preview')
9 | const PlaySound = require('./output/playSound')
10 |
11 | module.exports = {
12 | CopyToClipboard,
13 | OpenInBrowser,
14 | SendNotification,
15 | UserScript,
16 | OpenFile,
17 | ShowFile,
18 | ReloadConfig,
19 | Preview,
20 | PlaySound,
21 | }
22 |
--------------------------------------------------------------------------------
/app/blocks/output/copyToClipboard.js:
--------------------------------------------------------------------------------
1 | const electron = require('electron')
2 |
3 | const Template = require('../../lib/template')
4 | const Block = require('../block')
5 |
6 | class CopyToClipboard extends Block {
7 | constructor (data) {
8 | super(data)
9 | this.clipboard = electron.clipboard
10 | this.text = data.text || '{value}'
11 | }
12 |
13 | call (state) {
14 | this.logger.log('info', 'Copying to clipboard')
15 | this.clipboard.writeText(Template.compile(this.text, {
16 | value: String(state.value),
17 | }))
18 | return state.next()
19 | }
20 | }
21 |
22 | module.exports = CopyToClipboard
23 |
--------------------------------------------------------------------------------
/app/blocks/output/openFile.js:
--------------------------------------------------------------------------------
1 | const { shell } = require('electron')
2 | const os = require('os')
3 |
4 | const Block = require('../block')
5 |
6 | class OpenFile extends Block {
7 | constructor (data) {
8 | super(data)
9 | this.script = data.script
10 | this.cwd = data.cwd
11 | }
12 |
13 | call (state, env = {}) {
14 | const fullPath = state.value.replace(/^~/, os.homedir())
15 | this.logger.log('info', 'Opening File', { fullPath })
16 | shell.openItem(fullPath)
17 | return state.next()
18 | }
19 | }
20 |
21 | module.exports = OpenFile
22 |
--------------------------------------------------------------------------------
/app/blocks/output/openInBrowser.js:
--------------------------------------------------------------------------------
1 | const { shell } = require('electron')
2 |
3 | const Template = require('../../lib/template')
4 | const Block = require('../block')
5 |
6 | class OpenInBrowser extends Block {
7 | constructor (data) {
8 | super(data)
9 | this.url = data.url || '{value}'
10 | }
11 |
12 | call (state) {
13 | const url = Template.compile(this.url, {
14 | value: String(state.value),
15 | })
16 | this.logger.log('info', 'Opening in browser', { url })
17 | shell.openExternal(url)
18 | return state.next()
19 | }
20 | }
21 |
22 | module.exports = OpenInBrowser
23 |
--------------------------------------------------------------------------------
/app/blocks/output/playSound.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const Template = require('../../lib/template')
3 | const Block = require('../block')
4 |
5 | class PlaySound extends Block {
6 | constructor (data) {
7 | super(data)
8 | this.file = data.file
9 | this.cwd = data.cwd
10 | }
11 |
12 | call (state, env = {}) {
13 | const file = Template.compile(this.file, {
14 | value: String(state.value),
15 | })
16 | const fullPath = path.join(this.cwd, file)
17 |
18 | this.logger.log('info', 'Playing File', { fullPath })
19 |
20 | const audio = new Audio(fullPath)
21 | return new Promise((resolve) => {
22 | return audio.play().then(() => {
23 | audio.addEventListener('ended', resolve)
24 | })
25 | }).then(() => {
26 | return state.next()
27 | })
28 | }
29 | }
30 |
31 | module.exports = PlaySound
32 |
--------------------------------------------------------------------------------
/app/blocks/output/preview.js:
--------------------------------------------------------------------------------
1 | const Block = require('../block')
2 | const Template = require('../../lib/template')
3 | const { windowHelper } = require('../../helpers/window')
4 | const path = require('path')
5 | const Screens = require('../../lib/screens')
6 |
7 | class Preview extends Block {
8 | constructor (data) {
9 | super(data)
10 | this.message = data.message || '{value}'
11 | this.screens = Screens.getInstance({
12 | windowWidth: 700,
13 | })
14 | }
15 |
16 | call (state, env = {}) {
17 | const win = windowHelper('preview-block', {
18 | show: false,
19 | width: 700,
20 | height: 500,
21 | frame: false,
22 | resizable: false,
23 | autoResize: true,
24 | alwaysOnTop: true,
25 | skipTaskbar: true,
26 | title: 'Large Type',
27 | url: path.join('file://', path.dirname(path.dirname(__dirname)), '/preview.html'),
28 | webPreferences: {
29 | nodeIntegration: true,
30 | },
31 | })
32 | const position = this.screens.getCenterPositionOnCurrentScreen()
33 | if (position) {
34 | win.setPosition(position.x, position.y)
35 | }
36 | win.webContents.on('did-finish-load', () => {
37 | win.webContents.send('message', Template.compile(this.message, {
38 | value: String(state.value),
39 | }))
40 | })
41 | return new Promise((resolve) => {
42 | win.on('blur', () => {
43 | win.close()
44 | })
45 | win.on('close', () => {
46 | resolve()
47 | })
48 | }).then(() => {
49 | return state.next()
50 | })
51 | }
52 | }
53 |
54 | module.exports = Preview
55 |
--------------------------------------------------------------------------------
/app/blocks/output/reloadConfig.js:
--------------------------------------------------------------------------------
1 | const globalEmitter = require('../../lib/globalEmitter')
2 | const Block = require('../block')
3 |
4 | class ReloadConfig extends Block {
5 | constructor (data) {
6 | super(data)
7 | this.url = data.url || '{value}'
8 | }
9 |
10 | call () {
11 | this.logger.log('info', 'Reloading configuration')
12 | globalEmitter.emit('reloadConfig')
13 | return Promise.resolve()
14 | }
15 | }
16 |
17 | module.exports = ReloadConfig
18 |
--------------------------------------------------------------------------------
/app/blocks/output/sendNotification.js:
--------------------------------------------------------------------------------
1 | const notification = require('../../lib/notification')
2 | const Template = require('../../lib/template')
3 | const Block = require('../block')
4 |
5 | class SendNotification extends Block {
6 | constructor (data) {
7 | super(data)
8 | this.title = data.title || '{value}'
9 | this.message = data.message || '{value}'
10 | }
11 |
12 | call (state) {
13 | const variables = { value: String(state.value) }
14 | const options = {
15 | title: Template.compile(this.title, variables),
16 | message: Template.compile(this.message, variables),
17 | }
18 | this.logger.log('info', 'Notification', options)
19 | notification.push(options)
20 | return state.next()
21 | }
22 | }
23 |
24 | module.exports = SendNotification
25 |
--------------------------------------------------------------------------------
/app/blocks/output/showFile.js:
--------------------------------------------------------------------------------
1 | const { shell } = require('electron')
2 | const os = require('os')
3 |
4 | const Block = require('../block')
5 |
6 | class ShowFile extends Block {
7 | constructor (data) {
8 | super(data)
9 | this.script = data.script
10 | this.cwd = data.cwd
11 | }
12 |
13 | call (state, env = {}) {
14 | const fullPath = state.value.replace(/^~/, os.homedir())
15 | this.logger.log('info', 'Showing File', { fullPath })
16 | shell.showItemInFolder(fullPath)
17 | return state.next()
18 | }
19 | }
20 |
21 | module.exports = ShowFile
22 |
--------------------------------------------------------------------------------
/app/blocks/output/userScript.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const electron = require('electron')
3 |
4 | const Block = require('../block')
5 |
6 | class UserScript extends Block {
7 | constructor (data) {
8 | super(data)
9 | try {
10 | const plugin = electron.remote.require(path.join(data.cwd, data.script))
11 | this.script = plugin({
12 | console: this.logger,
13 | cwd: data.cwd,
14 | })
15 | } catch (e) {
16 | this.script = false
17 | this.loadError = e
18 | }
19 | }
20 |
21 | call (state, env = {}) {
22 | if (!this.script) {
23 | this.logger.error('Plugin failed to load', this.loadError)
24 | return Promise.resolve()
25 | }
26 | this.logger.log('verbose', 'Executing Script', { value: state.value })
27 | return this._ensurePromise(this.script(state.value, env)).then((output) => {
28 | state.value = output
29 | this.logger.log('info', 'User Script results', { value: state.value })
30 | return state.next()
31 | }).catch((error) => {
32 | this.logger.error('User Script failed', { value: state.value, error })
33 | })
34 | }
35 | }
36 |
37 | module.exports = UserScript
38 |
--------------------------------------------------------------------------------
/app/components/loadingSpinner.js:
--------------------------------------------------------------------------------
1 | const React = require('react')
2 | const PropTypes = require('prop-types')
3 |
4 | const Style = require('./style')
5 |
6 | const LoadingSpinner = ({ loaded, total }) => {
7 | let css = `
8 | body {
9 | background-color: #5CC7B2;
10 | margin: 0;
11 | }
12 | h2, h3 {
13 | margin: 0;
14 | padding: 10px;
15 | display: block;
16 | color: #fff;
17 | text-align: center;
18 | }
19 | `
20 |
21 | return (
22 |
23 |
Zazu is loading...
24 |
{loaded} of {total} plugins are loaded
25 |
27 |
28 |
29 |
30 |
55 |
56 |