├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc ├── README.md ├── build ├── build-plus.sh └── build.sh ├── config ├── utils.js ├── webpack.steward.config.js └── webpack.stewardplus.config.js ├── docs └── index.html ├── extension ├── _locales │ ├── en │ │ └── messages.json │ └── zh_CN │ │ └── messages.json ├── collection │ ├── component.ts │ ├── diary.ts │ ├── plugin.ts │ ├── website.ts │ └── workflow.ts ├── common │ ├── auth.ts │ ├── config.ts │ ├── events.ts │ ├── request.ts │ ├── steward.ts │ ├── storage.ts │ ├── type.ts │ └── util.ts ├── components │ ├── application │ │ └── index.vue │ ├── cmdbox │ │ └── index.vue │ ├── easycomplete │ │ ├── easycompleteItem.vue │ │ ├── index.vue │ │ └── mockData.js │ └── jsoneditor │ │ └── index.vue ├── conf │ ├── general.ts │ ├── index.ts │ ├── pocket_conf.ts │ └── themes.ts ├── constant │ ├── base.ts │ ├── code.ts │ ├── i18n.ts │ ├── index.ts │ ├── keycode.ts │ ├── number.ts │ ├── options.ts │ └── storage.ts ├── css │ └── base.css ├── enum │ ├── bookmarkTag.ts │ ├── index.ts │ ├── messageType.ts │ ├── pageAction.ts │ └── pageCommand.ts ├── helper │ ├── action.helper.ts │ ├── alias.helper.ts │ ├── component.helper.ts │ ├── config.helper.ts │ ├── diary.helper.ts │ ├── editor.helper.ts │ ├── extension.helper.ts │ ├── i18n.helper.ts │ ├── index.ts │ ├── plugin.helper.ts │ ├── result.helper.ts │ ├── storage.helper.ts │ ├── theme.helper.ts │ ├── wallpaper.helper.ts │ ├── wallpaperSource.helper.ts │ ├── websites.helper.ts │ └── workflow.helper.ts ├── img │ ├── icon.png │ ├── icon128.png │ ├── icon16.png │ ├── icon48.png │ ├── jenkins │ │ ├── aborted.png │ │ ├── blue.png │ │ ├── health-00to19.png │ │ ├── health-20to39.png │ │ ├── health-40to59.png │ │ ├── health-60to79.png │ │ ├── health-80plus.png │ │ ├── nobuilt.png │ │ └── red.png │ └── wordcard.png ├── info │ ├── changelog.ts │ ├── help.ts │ ├── i18n.ts │ └── links.ts ├── lib │ ├── backbone.chromestorage.ts │ └── social-share-urls.ts ├── main │ ├── Steward.ts │ ├── cache.ts │ ├── main.ts │ ├── type.ts │ └── wallpaper.ts ├── manifest-plus.json ├── manifest.json ├── pages │ ├── background │ │ ├── background.ejs │ │ └── index.ts │ ├── content │ │ ├── content.ejs │ │ ├── content.scss │ │ ├── index.ts │ │ └── pageService.ts │ ├── login │ │ ├── index.ts │ │ └── login.ejs │ ├── options │ │ ├── App.vue │ │ ├── index.js │ │ ├── options.ejs │ │ ├── preview.html │ │ ├── router │ │ │ └── index.js │ │ └── views │ │ │ ├── Advanced.vue │ │ │ ├── Appearance.vue │ │ │ ├── General.vue │ │ │ ├── Help.vue │ │ │ ├── Newtabcomponents.vue │ │ │ ├── Plugins.vue │ │ │ ├── Update.vue │ │ │ ├── Wallpapers.vue │ │ │ ├── Websites.vue │ │ │ └── Workflows.vue │ ├── popup │ │ ├── App.vue │ │ ├── index.js │ │ └── popup.ejs │ ├── steward │ │ ├── App.vue │ │ ├── index.js │ │ └── steward.ejs │ └── urlblock │ │ ├── index.ts │ │ └── urlblock.ejs ├── plugins │ ├── browser │ │ ├── bookmark.ts │ │ ├── chrome.ts │ │ ├── del.ts │ │ ├── download.ts │ │ ├── extensions.ts │ │ ├── his.ts │ │ ├── off.ts │ │ ├── on.ts │ │ ├── run.ts │ │ ├── set.ts │ │ ├── tab.ts │ │ └── topsites.ts │ ├── extension │ │ └── wordcard.ts │ ├── index.ts │ ├── other │ │ ├── calculate.ts │ │ ├── diary.ts │ │ ├── note.ts │ │ ├── openurl.ts │ │ ├── pocket.ts │ │ ├── search.ts │ │ ├── todo.ts │ │ └── urlblock.ts │ ├── steward │ │ ├── about.ts │ │ ├── component.ts │ │ ├── custom.ts │ │ ├── help.ts │ │ ├── newtab.ts │ │ ├── random.ts │ │ ├── spm.ts │ │ ├── steward.ts │ │ ├── wallpaper.ts │ │ ├── workflow.ts │ │ └── wsm.ts │ └── type.ts ├── scripts │ ├── newtab.js │ └── popup.js ├── scss │ ├── main.scss │ └── themes │ │ ├── base.scss │ │ ├── newtab │ │ └── classical.scss │ │ └── popup │ │ └── classical.scss ├── server │ ├── controller │ │ └── recordsController.ts │ └── db │ │ └── index.ts ├── service │ ├── bing.ts │ ├── desktoppr.ts │ ├── index.ts │ ├── nasa.ts │ ├── picsum.ts │ ├── pixabay.ts │ └── selection.ts ├── svg │ ├── alias.svg │ ├── allowbatch.svg │ ├── app.svg │ ├── author.svg │ ├── baidu.svg │ ├── bbs.svg │ ├── bing.svg │ ├── bookmark.svg │ ├── btc.svg │ ├── calc.svg │ ├── chrome.svg │ ├── copy.svg │ ├── del.svg │ ├── delete-icon.svg │ ├── diary.svg │ ├── download-red.svg │ ├── download.svg │ ├── enter-white.svg │ ├── enter.svg │ ├── exts │ │ └── wordcard │ │ │ ├── level0.svg │ │ │ ├── level1.svg │ │ │ ├── level2.svg │ │ │ ├── level3.svg │ │ │ ├── level4.svg │ │ │ ├── level5.svg │ │ │ └── tag.svg │ ├── github.svg │ ├── google.svg │ ├── help.svg │ ├── history.svg │ ├── iframe.svg │ ├── index.svg │ ├── jenkins.svg │ ├── loading.svg │ ├── miniapp.svg │ ├── new-tab.svg │ ├── newversion.svg │ ├── note.svg │ ├── notshow.svg │ ├── off.svg │ ├── on.svg │ ├── openurl.svg │ ├── plus.svg │ ├── plusone.svg │ ├── pm25.svg │ ├── random.svg │ ├── refresh-red.svg │ ├── refresh.svg │ ├── save-red.svg │ ├── selected-icon.svg │ ├── set.svg │ ├── share-icons │ │ ├── baidu.svg │ │ ├── blogger.svg │ │ ├── buffer.svg │ │ ├── delicious.svg │ │ ├── digg.svg │ │ ├── douban.svg │ │ ├── evernote.svg │ │ ├── facebook.svg │ │ ├── flipboard.svg │ │ ├── friendfeed.svg │ │ ├── getpocket.svg │ │ ├── google_plus.svg │ │ ├── instapaper.svg │ │ ├── line.me.svg │ │ ├── linkedin.svg │ │ ├── livejournal.svg │ │ ├── myspace.svg │ │ ├── newsvine.svg │ │ ├── pinterest.svg │ │ ├── qzone.svg │ │ ├── reddit.svg │ │ ├── renren.svg │ │ ├── skype.svg │ │ ├── stumbleupon.svg │ │ ├── telegram_me.svg │ │ ├── tumblr.svg │ │ ├── twitter.svg │ │ ├── viber.svg │ │ ├── weibo.svg │ │ ├── whatsapp.svg │ │ ├── xing.svg │ │ └── yahoo.svg │ ├── sspai.svg │ ├── stackoverflow.svg │ ├── star-fill.svg │ ├── star.svg │ ├── tab.svg │ ├── todo.svg │ ├── topsites.svg │ ├── urlblock.svg │ ├── viewext.svg │ ├── wallpaper-icon.svg │ ├── weather.svg │ ├── weibo-red.svg │ ├── weibo.svg │ ├── workflow.svg │ ├── youdao.svg │ └── zhihu.svg └── utils │ ├── api.ts │ ├── date.ts │ ├── index.ts │ ├── object.ts │ └── storage.ts ├── jsconfig.json ├── package.json ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env", { 3 | "targets": { 4 | "chrome": "59" 5 | } 6 | }]] 7 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | !/*.js 2 | /extension/lib/ 3 | /output/ 4 | /config/ 5 | /extension/js/common/ga.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:vue/essential" 10 | ], 11 | "globals": { 12 | "Atomics": "readonly", 13 | "SharedArrayBuffer": "readonly", 14 | "chrome": true, 15 | "EXT_TYPE": true 16 | }, 17 | "parserOptions": { 18 | "ecmaVersion": 2018, 19 | "parser": "babel-eslint", 20 | "sourceType": "module" 21 | }, 22 | "plugins": [ 23 | "vue" 24 | ], 25 | "rules": { 26 | "no-inner-declarations": "off", 27 | "no-empty": "off" 28 | } 29 | }; -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [solobat] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: tomasy 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: https://paypal.me/tomasy/5 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project related 2 | output 3 | .private 4 | 5 | ### node etc ### 6 | 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | 17 | #For ionic build 18 | platforms/ 19 | www/lib 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Dependency directorys 31 | # Deployed apps should consider commenting these lines out: 32 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 33 | node_modules/ 34 | bower_components/ 35 | package-lock.json 36 | 37 | 38 | # Packages # 39 | ############ 40 | # it's better to unpack these files and commit the raw source 41 | # git has its own built in compression methods 42 | *.7z 43 | *.dmg 44 | *.gz 45 | *.iso 46 | *.jar 47 | *.rar 48 | *.tar 49 | *.zip 50 | 51 | 52 | 53 | # OS generated files # 54 | ###################### 55 | .DS_Store 56 | .DS_Store? 57 | ._* 58 | .Spotlight-V100 59 | .Trashes 60 | ehthumbs.db 61 | Thumbs.db 62 | 63 | # Text Editors 64 | *.vscode 65 | *.sublime 66 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "trailingComma": "all", 6 | "useTabs": false 7 | } -------------------------------------------------------------------------------- /build/build-plus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # prepare 4 | echo "准备目录......" 5 | rm -fr output 6 | mkdir -p output 7 | 8 | # build 9 | echo "编译中....." 10 | npm run build:minified:plus || { echo "编译失败,请检查后重试"; exit 1; } 11 | 12 | zip -r stewardplus.zip output/steward_plus/ 13 | 14 | echo "打包完毕" 15 | 16 | mv -f stewardplus.zip ~/Desktop 17 | 18 | echo "移动到桌面" -------------------------------------------------------------------------------- /build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # prepare 4 | echo "准备目录......" 5 | rm -fr output 6 | mkdir -p output 7 | 8 | # build 9 | echo "编译中....." 10 | npm run build:minified || { echo "编译失败,请检查后重试"; exit 1; } 11 | 12 | zip -r steward.zip output/steward/ 13 | 14 | echo "打包完毕" 15 | 16 | mv -f steward.zip ~/Desktop 17 | 18 | echo "移动到桌面" -------------------------------------------------------------------------------- /config/utils.js: -------------------------------------------------------------------------------- 1 | const glob = require("glob") 2 | const path = require('path') 3 | const HtmlWebpackPlugin = require('html-webpack-plugin') 4 | 5 | const pages = [] 6 | const entries = {} 7 | 8 | glob.sync("./extension/pages/*/index.*s").forEach(pagePath => { 9 | const chunk = pagePath.split('pages/')[1].split("/index.")[0] 10 | 11 | entries[chunk] = pagePath 12 | pages.push(new HtmlWebpackPlugin({ 13 | title: `Steward - ${chunk}`, 14 | template: `./extension/pages/${chunk}/${chunk}.ejs`, 15 | filename: `${chunk}.html`, 16 | inject: true, 17 | chunksSortMode: 'auto', 18 | chunks: ['manifest', 'vendor', 'common', chunk] 19 | })) 20 | }) 21 | 22 | module.exports = { 23 | pages, 24 | entries 25 | } -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation 8 | 9 | 10 |
11 | 12 |
13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /extension/collection/component.ts: -------------------------------------------------------------------------------- 1 | 2 | import Backbone from 'backbone'; 3 | 4 | import ChromeStorage from '../lib/backbone.chromestorage'; 5 | 6 | export const Component = Backbone.Model.extend({ 7 | sync: Backbone.sync, 8 | defaults: function() { 9 | return { 10 | created: Number(new Date()), 11 | updated: Number(new Date()), 12 | }; 13 | }, 14 | }); 15 | 16 | export const ComponentList = Backbone.Collection.extend({ 17 | model: Component, 18 | 19 | chromeStorage: new ChromeStorage('components', 'local'), 20 | 21 | nextOrder: function() { 22 | if (!this.length) { 23 | return 1; 24 | } 25 | return this.last().get('created') + 1; 26 | }, 27 | 28 | comparator: 'created', 29 | }); 30 | -------------------------------------------------------------------------------- /extension/collection/diary.ts: -------------------------------------------------------------------------------- 1 | 2 | import Backbone from 'backbone'; 3 | 4 | import ChromeStorage from '../lib/backbone.chromestorage'; 5 | 6 | export const Diary = Backbone.Model.extend({ 7 | sync: Backbone.sync, 8 | defaults: function() { 9 | return { 10 | created: Number(new Date()), 11 | updated: Number(new Date()), 12 | }; 13 | }, 14 | }); 15 | 16 | export const DiaryList = Backbone.Collection.extend({ 17 | model: Diary, 18 | 19 | chromeStorage: new ChromeStorage('diarylist', 'local'), 20 | 21 | nextOrder: function() { 22 | if (!this.length) { 23 | return 1; 24 | } 25 | return this.last().get('created') + 1; 26 | }, 27 | 28 | comparator: 'created', 29 | }); 30 | -------------------------------------------------------------------------------- /extension/collection/plugin.ts: -------------------------------------------------------------------------------- 1 | 2 | import Backbone from 'backbone'; 3 | 4 | import ChromeStorage from '../lib/backbone.chromestorage'; 5 | 6 | export const CustomPlugin = Backbone.Model.extend({ 7 | sync: Backbone.sync, 8 | defaults: function() { 9 | return { 10 | created: Number(new Date()), 11 | updated: Number(new Date()), 12 | }; 13 | }, 14 | }); 15 | 16 | export const CustomPluginList = Backbone.Collection.extend({ 17 | model: CustomPlugin, 18 | 19 | chromeStorage: new ChromeStorage('custompluginlist', 'local'), 20 | 21 | nextOrder: function() { 22 | if (!this.length) { 23 | return 1; 24 | } 25 | return this.last().get('created') + 1; 26 | }, 27 | 28 | comparator: 'created', 29 | }); 30 | -------------------------------------------------------------------------------- /extension/collection/website.ts: -------------------------------------------------------------------------------- 1 | import Backbone from 'backbone'; 2 | 3 | import ChromeStorage from '../lib/backbone.chromestorage'; 4 | 5 | export const Website = Backbone.Model.extend({ 6 | sync: Backbone.sync, 7 | defaults: function() { 8 | return { 9 | created: Number(new Date()), 10 | updated: Number(new Date()), 11 | }; 12 | }, 13 | }); 14 | 15 | export const WebsiteList = Backbone.Collection.extend({ 16 | model: Website, 17 | 18 | chromeStorage: new ChromeStorage('websites', 'local'), 19 | 20 | nextOrder: function() { 21 | if (!this.length) { 22 | return 1; 23 | } 24 | return this.last().get('created') + 1; 25 | }, 26 | 27 | comparator: 'created', 28 | }); 29 | -------------------------------------------------------------------------------- /extension/collection/workflow.ts: -------------------------------------------------------------------------------- 1 | import Backbone from 'backbone'; 2 | 3 | import ChromeStorage from '../lib/backbone.chromestorage'; 4 | 5 | export const Workflow = Backbone.Model.extend({ 6 | sync: Backbone.sync, 7 | defaults: function() { 8 | return { 9 | created: Number(new Date()), 10 | updated: Number(new Date()), 11 | }; 12 | }, 13 | }); 14 | 15 | export const WorkflowList = Backbone.Collection.extend({ 16 | model: Workflow, 17 | 18 | chromeStorage: new ChromeStorage('workflows', 'sync'), 19 | 20 | nextOrder: function() { 21 | if (!this.length) { 22 | return 1; 23 | } 24 | return this.last().get('created') + 1; 25 | }, 26 | 27 | comparator: 'created', 28 | }); 29 | -------------------------------------------------------------------------------- /extension/common/events.ts: -------------------------------------------------------------------------------- 1 | 2 | import $ from 'jquery'; 3 | 4 | const events = { 5 | tabs: { 6 | onRemoved: function(cb) { 7 | chrome.tabs.onRemoved.addListener(function(...args) { 8 | Reflect.apply(cb, null, args); 9 | }); 10 | }, 11 | 12 | onCreated: function(cb) { 13 | chrome.tabs.onCreated.addListener(function(...args) { 14 | Reflect.apply(cb, null, args); 15 | }); 16 | }, 17 | }, 18 | 19 | windows: { 20 | onCreated: function(cb) { 21 | chrome.windows.onCreated.addListener(function(...args) { 22 | Reflect.apply(cb, null, args); 23 | }); 24 | }, 25 | }, 26 | }; 27 | 28 | function trigger(obj, actionFn) { 29 | $.each(obj, function(eventType, eventList) { 30 | if (!eventList.length) { 31 | return; 32 | } 33 | 34 | const allTypeEvents = events[eventType]; 35 | for (let i = 0, len = eventList.length; i < len; i = i + 1) { 36 | allTypeEvents[eventList[i]](actionFn); 37 | } 38 | }); 39 | } 40 | 41 | export default { 42 | on: trigger, 43 | }; 44 | -------------------------------------------------------------------------------- /extension/common/request.ts: -------------------------------------------------------------------------------- 1 | 2 | function emptyFn() {} 3 | 4 | function send(obj, callback = (res: any) => {}) { 5 | chrome.extension.sendRequest(obj || {}, function(response) { 6 | callback(response); 7 | }); 8 | } 9 | 10 | function log(msg) { 11 | send( 12 | { 13 | msg: msg, 14 | }, 15 | emptyFn, 16 | ); 17 | } 18 | 19 | function get(cb) { 20 | chrome.extension.onRequest.addListener(function(...args) { 21 | Reflect.apply(cb, null, args); 22 | }); 23 | } 24 | 25 | export default { 26 | send, 27 | log, 28 | get, 29 | }; 30 | -------------------------------------------------------------------------------- /extension/common/steward.ts: -------------------------------------------------------------------------------- 1 | 2 | export function getSteward() { 3 | return window.__Steward__; 4 | } 5 | 6 | export function getOptionsPage() { 7 | return window.optionsPage; 8 | } -------------------------------------------------------------------------------- /extension/common/storage.ts: -------------------------------------------------------------------------------- 1 | 2 | const h5 = { 3 | set: function(key: string, value) { 4 | localStorage[key] = value; 5 | }, 6 | 7 | get: function(key: string) { 8 | return localStorage[key]; 9 | }, 10 | }; 11 | 12 | function baseSet(type, data, cb) { 13 | chrome.storage[type].set(data, function(...args) { 14 | Reflect.apply(cb, this, args); 15 | }); 16 | } 17 | 18 | function baseGet(type, key, cb) { 19 | chrome.storage[type].get(key, function(...args) { 20 | Reflect.apply(cb, this, args); 21 | }); 22 | } 23 | 24 | const local = { 25 | set: function(data, cb) { 26 | baseSet('local', data, cb); 27 | }, 28 | 29 | get: function(key, cb) { 30 | baseGet('sync', key, cb); 31 | }, 32 | }; 33 | 34 | const sync = { 35 | set: function(data, cb) { 36 | baseSet('sync', data, cb); 37 | }, 38 | 39 | get: function(key, cb) { 40 | baseGet('sync', key, cb); 41 | }, 42 | }; 43 | 44 | export default { 45 | h5, 46 | local, 47 | sync, 48 | }; 49 | -------------------------------------------------------------------------------- /extension/components/easycomplete/easycompleteItem.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /extension/components/easycomplete/mockData.js: -------------------------------------------------------------------------------- 1 | import { getURL } from "helper/extension.helper"; 2 | 3 | export const dataList = [{ 4 | key: 'plugins', 5 | title: '测试个鬼', 6 | icon: getURL('img/icon.png'), 7 | desc: '描述个鬼', 8 | url: 'https://baidu.com' 9 | }, { 10 | key: 'plugins', 11 | title: '测试个鬼1', 12 | icon: getURL('img/icon.png'), 13 | desc: '描述个鬼', 14 | url: 'https://baidu.com' 15 | }, { 16 | key: 'plugins', 17 | title: '测试个鬼2', 18 | icon: getURL('img/icon.png'), 19 | desc: '描述个鬼', 20 | url: 'https://baidu.com' 21 | }, { 22 | key: 'plugins', 23 | title: '测试个鬼3', 24 | icon: getURL('img/icon.png'), 25 | desc: '描述个鬼', 26 | url: 'https://baidu.com' 27 | }, { 28 | key: 'plugins', 29 | title: '测试个鬼4', 30 | icon: getURL('img/icon.png'), 31 | desc: '描述个鬼', 32 | url: 'https://baidu.com' 33 | }, { 34 | key: 'plugins', 35 | title: '测试个鬼5', 36 | icon: getURL('img/icon.png'), 37 | desc: '描述个鬼', 38 | url: 'https://baidu.com' 39 | }, { 40 | key: 'plugins', 41 | title: '测试个鬼6', 42 | icon: getURL('img/icon.png'), 43 | desc: '描述个鬼', 44 | url: 'https://baidu.com' 45 | }, { 46 | key: 'plugins', 47 | title: '测试个鬼7', 48 | icon: getURL('img/icon.png'), 49 | desc: '描述个鬼', 50 | url: 'https://baidu.com' 51 | }, { 52 | key: 'plugins', 53 | title: '测试个鬼8', 54 | icon: getURL('img/icon.png'), 55 | desc: '描述个鬼', 56 | url: 'https://baidu.com' 57 | }, { 58 | key: 'plugins', 59 | title: '测试个鬼9', 60 | icon: getURL('img/icon.png'), 61 | desc: '描述个鬼', 62 | url: 'https://baidu.com' 63 | }, { 64 | key: 'plugins', 65 | title: '测试个鬼10', 66 | icon: getURL('img/icon.png'), 67 | desc: '描述个鬼', 68 | url: 'https://baidu.com' 69 | }, { 70 | key: 'plugins', 71 | title: '测试个鬼11', 72 | icon: getURL('img/icon.png'), 73 | desc: '描述个鬼', 74 | url: 'https://baidu.com' 75 | }]; 76 | -------------------------------------------------------------------------------- /extension/components/jsoneditor/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 68 | -------------------------------------------------------------------------------- /extension/conf/general.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | cacheLastCmd: true, 3 | defaultPlugin: '', 4 | customCmd: '', 5 | autoScrollToMiddle: false, 6 | speedFirst: false, 7 | autoHideCmd: false, 8 | maxOperandsNum: 5, 9 | autoResizeBoxFontSize: false, 10 | wallpaperSources: ['bing', 'favorites'], 11 | newtabWidgets: ['wpbtns'], 12 | autoSelectByMouse: false, 13 | enableRandomWallpaper: true, 14 | storeTypedQuery: true, 15 | autoCreateWebsite: true, 16 | websiteUrls: true, 17 | componentsMirror: 'github', 18 | websiteShareUrls: true, 19 | emptyCommand: '', 20 | shortcuts: { 21 | 'open-in-content-page': { cmd: '' }, 22 | pageboxShortcut_0: { cmd: 'his ' }, 23 | pageboxShortcut_1: { cmd: 'tab ' }, 24 | pageboxShortcut_2: { cmd: 'bm ' }, 25 | pageboxShortcut_3: { cmd: 'wf ' }, 26 | pageboxShortcut_4: { cmd: 'tabp ' }, 27 | pageboxShortcut_5: { cmd: 'tabm ' }, 28 | pageboxShortcut_6: { cmd: "'" }, 29 | pageboxShortcut_7: { cmd: '`' }, 30 | pageboxShortcut_8: { cmd: 'tq ' }, 31 | pageboxShortcut_9: { cmd: ': ' }, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /extension/conf/index.ts: -------------------------------------------------------------------------------- 1 | import { getOptionsPage, getSteward } from 'common/steward'; 2 | import { getValueByPath } from 'utils/object'; 3 | 4 | export function getAppConfig(path, defaultValue) { 5 | return getValueByPath((getSteward() || getOptionsPage()).config, path, defaultValue); 6 | } 7 | -------------------------------------------------------------------------------- /extension/conf/pocket_conf.ts: -------------------------------------------------------------------------------- 1 | import { getURL } from "helper/extension.helper"; 2 | 3 | export default { 4 | consumer_key: '36254-48fd5cd99b53d0e9cfabbee0', 5 | requestUrl: 'https://getpocket.com/v3/oauth/request', 6 | authenticateUrl: 'https://getpocket.com/auth/authorize', 7 | accessTokenUrl: 'https://getpocket.com/v3/oauth/authorize', 8 | redirect_uri: getURL('login.html'), 9 | appName: 'pocket', 10 | }; 11 | -------------------------------------------------------------------------------- /extension/constant/base.ts: -------------------------------------------------------------------------------- 1 | export const PLUGIN_TYPE = { 2 | ALWAYS: 'always', 3 | REGEXP: 'regexp', 4 | KEYWORD: 'keyword', 5 | OTHER: 'other', 6 | SEARCH: 'search', 7 | }; 8 | 9 | export const EMPTY_COMMAND = '_empty_'; 10 | 11 | export const ITEM_TYPE = { 12 | PLUGINS: 'plugins', 13 | URL: 'url', 14 | COPY: 'copy', 15 | ACTION: 'action', 16 | APP: 'app', 17 | }; 18 | 19 | export const MODE = { 20 | NEWTAB: 'newTab', 21 | POPUP: 'popup', 22 | }; 23 | 24 | export const EXTENSION = { 25 | STEWARD: 'steward', 26 | STEWARDPLUS: 'stewardplus', 27 | }; 28 | 29 | export const PLUGIN_STATUS = { 30 | NOTINSTALL: 0, 31 | NEWVESION: 1, 32 | INSTALLED: 2, 33 | }; 34 | 35 | export const WEBSITE_STATUS = { 36 | NOTINSTALL: 0, 37 | NEWVESION: 1, 38 | INSTALLED: 2, 39 | }; 40 | 41 | export const stewardTabs = [ 42 | 'Steward', 43 | 'General', 44 | 'Plugins', 45 | 'Workflows', 46 | 'Websites', 47 | 'Wallpapers', 48 | 'Appearance', 49 | 'Advanced', 50 | 'Help', 51 | 'Update', 52 | ]; 53 | 54 | export const stewardPlusTabs = [ 55 | 'Steward', 56 | 'General', 57 | 'Plugins', 58 | 'Workflows', 59 | 'Websites', 60 | 'NewtabComponents', 61 | 'Wallpapers', 62 | 'Appearance', 63 | 'Advanced', 64 | 'Help', 65 | 'Update', 66 | ]; 67 | -------------------------------------------------------------------------------- /extension/constant/code.ts: -------------------------------------------------------------------------------- 1 | export const PLUGIN_DEFAULT = ` 2 | module.exports = function (steward) { 3 | const version = 1; 4 | const author = 'solobat'; 5 | const name = 'yourPlugin'; 6 | const key = 'xxx'; 7 | const type = 'keyword'; 8 | const icon = 'http://static.oksteward.com/icon128.png'; 9 | const title = 'your plugin'; 10 | const subtitle = 'custom your plugin'; 11 | const commands = [{ 12 | key, 13 | type, 14 | title, 15 | subtitle, 16 | icon 17 | }]; 18 | 19 | function onInput(query, command) { 20 | // return a promise 21 | return Promise.resolve([ 22 | { 23 | icon, 24 | key: 1, 25 | title: 'result 1', 26 | desc: 'desc 1' 27 | }, 28 | { 29 | icon, 30 | key: 2, 31 | title: 'result 2', 32 | desc: 'desc 2' 33 | } 34 | ]); 35 | } 36 | 37 | function onEnter(item, command, query, keyStatus, list) { 38 | steward.util.copyToClipboard(item.title, true); 39 | } 40 | 41 | return { 42 | author, 43 | version, 44 | name, 45 | category: 'other', 46 | icon, 47 | title, 48 | commands, 49 | onInput, 50 | onEnter 51 | }; 52 | } 53 | `; 54 | -------------------------------------------------------------------------------- /extension/constant/i18n.ts: -------------------------------------------------------------------------------- 1 | 2 | export const TIPS = { 3 | autoScrollToMiddle: 'autoScrollToMiddle', 4 | autoHideCmd: 'autoHideCmd', 5 | maxOperandsNum: 'maxOperandsNum', 6 | allowBatch: 'allowBatch', 7 | bm_shift: 'bm_shift', 8 | his_shift: 'his_shift', 9 | site_shift: 'site_shift', 10 | tabc_shift: 'tabc_shift', 11 | wd_shift: 'wd_shift', 12 | storeTypedQuery: 'storeTypedQuery', 13 | }; 14 | -------------------------------------------------------------------------------- /extension/constant/index.ts: -------------------------------------------------------------------------------- 1 | import * as BASE from './base'; 2 | import * as CODE from './code'; 3 | import * as I18N from './i18n'; 4 | import KEY from './keycode'; 5 | import * as NUMBER from './number'; 6 | import * as OPTIONS from './options'; 7 | import STORAGE from './storage'; 8 | 9 | export default { 10 | BASE, 11 | KEY, 12 | NUMBER, 13 | STORAGE, 14 | OPTIONS, 15 | I18N, 16 | CODE, 17 | }; 18 | -------------------------------------------------------------------------------- /extension/constant/keycode.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | TAB: 9, 3 | ENTER: 13, 4 | SHIFT: 16, 5 | CTRL: 17, 6 | ALT: 18, 7 | LEFT: 37, 8 | UP: 38, 9 | RIGHT: 39, 10 | DOWN: 40, 11 | NUM0: 49, 12 | NUM9: 57, 13 | }; 14 | -------------------------------------------------------------------------------- /extension/constant/number.ts: -------------------------------------------------------------------------------- 1 | export const WALLPAPER_INTERVAL = 5 * 60 * 1000; 2 | 3 | export const QUOTA_BYTES_PER_ITEM = 8192; 4 | 5 | export const MAX_WORKFLOW_NUM = 20; 6 | -------------------------------------------------------------------------------- /extension/constant/options.ts: -------------------------------------------------------------------------------- 1 | export const APPEARANCE_ITEMS = [ 2 | { 3 | name: 'New Tab', 4 | }, 5 | { 6 | name: 'Popup', 7 | }, 8 | { 9 | name: 'Page', 10 | }, 11 | ]; 12 | 13 | export const DEFAULT_PLUGINS = [ 14 | 'Top Sites', 15 | 'Bookmarks', 16 | 'Tabs', 17 | 'Weather', 18 | 'Other', 19 | 'Random', 20 | ].map(name => { 21 | return { 22 | label: name, 23 | value: name, 24 | }; 25 | }); 26 | 27 | export const WALLPAPER_SOURCES = [ 28 | { 29 | label: 'Favorites', 30 | value: 'favorites', 31 | tips: 'Your favorites', 32 | }, 33 | { 34 | label: 'Bing', 35 | value: 'bing', 36 | tips: 'faster, but less', 37 | }, 38 | { 39 | label: 'Unsplash', 40 | value: 'picsum', 41 | tips: 'lower, but more', 42 | }, 43 | { 44 | label: 'Nasa', 45 | value: 'nasa', 46 | tips: 'NASA', 47 | }, 48 | { 49 | label: 'Desktoppr', 50 | value: 'desktoppr', 51 | tips: 'desktoppr.co', 52 | }, 53 | { 54 | label: 'Pixabay', 55 | value: 'pixabay', 56 | tips: 'pixabay.com', 57 | }, 58 | { 59 | label: 'Solid Colors', 60 | value: 'solidcolor', 61 | }, 62 | { 63 | label: "Author's Selection", 64 | value: 'selection', 65 | }, 66 | ]; 67 | 68 | export const NEWTAB_WIDGETS = [ 69 | { 70 | label: 'Clock', 71 | value: 'clock', 72 | tips: 'Clock', 73 | }, 74 | { 75 | label: 'Shortcuts', 76 | value: 'shortcuts', 77 | tips: 'Shortcuts', 78 | }, 79 | { 80 | label: 'Bottom Buttons', 81 | value: 'wpbtns', 82 | tips: 'Bottom Buttons', 83 | }, 84 | ]; 85 | 86 | export const MIRRORS = [ 87 | { 88 | id: 'github', 89 | name: 'Github', 90 | baseURL: 91 | 'https://raw.githubusercontent.com/Steward-launcher/steward-newtab-components/master', 92 | }, 93 | { 94 | id: 'gitee', 95 | name: 'Gitee', 96 | baseURL: 97 | 'https://gitee.com/Steward-launcher/steward-newtab-components/raw/master', 98 | }, 99 | ]; 100 | -------------------------------------------------------------------------------- /extension/constant/storage.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | LAST_CMD: 'mw_last_cmd', 3 | LASTDATE: 'lastDate', 4 | WALLPAPER: 'wallpaper', 5 | WALLPAPERS: 'wallpapers', 6 | WALLPAPER_BLACKLIST: 'wallpaper_blacklist', 7 | THEMES: 'themes', 8 | TODO: 'todo', 9 | DONE: 'done', 10 | URL: 'url', 11 | CONFIG: 'config', 12 | NOTES: 'notes', 13 | TAGS: 'tags', 14 | TIMES: 'times', 15 | DIARY: 'diary', 16 | URLBLOCK_REPLACE_PAGE: 'urlblock_replace_page', 17 | }; 18 | -------------------------------------------------------------------------------- /extension/css/base.css: -------------------------------------------------------------------------------- 1 | [v-cloak] { 2 | display: none; 3 | } -------------------------------------------------------------------------------- /extension/enum/bookmarkTag.ts: -------------------------------------------------------------------------------- 1 | export enum BookMarkTag { 2 | TODO = 'TODO:', 3 | READ = 'READ:', 4 | TRY = 'TRY:', 5 | } 6 | -------------------------------------------------------------------------------- /extension/enum/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bookmarkTag'; 2 | export * from './messageType'; 3 | export * from './pageAction'; 4 | export * from './pageCommand'; 5 | -------------------------------------------------------------------------------- /extension/enum/messageType.ts: -------------------------------------------------------------------------------- 1 | export enum MessageType { 2 | TOGGLE_BOOKMARK = 'toggleBookmark', 3 | SHOW = 'show', 4 | INIT = 'init', 5 | NAVS = 'navs', 6 | OUTLINE = 'outline', 7 | ANCHORS = 'anchors', 8 | REPLACE_URL = 'replaceURL', 9 | IFRAMES = 'iframes', 10 | } 11 | -------------------------------------------------------------------------------- /extension/enum/pageAction.ts: -------------------------------------------------------------------------------- 1 | export enum PageAction { 2 | CLOSE_BOX = 'closeBox', 3 | BOX_INITED = 'boxInited', 4 | COMMAND = 'command', 5 | QUERY_NAVS = 'queryNavs', 6 | GEN_OUTLINE = 'genOutline', 7 | GET_ANCHORS = 'getAnchors', 8 | GET_META = 'getMeta', 9 | GET_IFRAMES = 'getIframes', 10 | } 11 | -------------------------------------------------------------------------------- /extension/enum/pageCommand.ts: -------------------------------------------------------------------------------- 1 | export enum PageCommand { 2 | OUTLINE = 'outline', 3 | ANCHOR = 'anchor', 4 | CLICK = 'click', 5 | HIDE = 'hide', 6 | SHOW = 'show', 7 | COPY = 'copy', 8 | PAGE_PROTECT = 'pageprotect', 9 | TOGGLE_TODO = 'toggleTodo', 10 | ENGLISH_SYNTAX_HIGHLIGHT = 'englishSyntaxHighlight', 11 | READ_MODE = 'readMode', 12 | } 13 | -------------------------------------------------------------------------------- /extension/helper/action.helper.ts: -------------------------------------------------------------------------------- 1 | import { Action } from 'plugins/type'; 2 | import { browser } from 'webextension-polyfill-ts'; 3 | 4 | import { PageCommand } from '../enum'; 5 | 6 | const defaultActions: Action[] = [ 7 | { 8 | title: 'Copy title as a markdown link', 9 | actionType: PageCommand.COPY, 10 | extend: { 11 | template: '[{{title}}]({{url}})', 12 | }, 13 | enable: true, 14 | }, 15 | { 16 | title: 'Copy selection text as a markdown link', 17 | actionType: PageCommand.COPY, 18 | extend: { 19 | template: '[{{selection}}]({{url}})', 20 | }, 21 | enable: false, 22 | }, 23 | { 24 | title: 'Toggle TODO', 25 | desc: 'Add a bookmark and tag it with a TODO prefix / Remove bookmark', 26 | actionType: PageCommand.TOGGLE_TODO, 27 | enable: true, 28 | }, 29 | { 30 | title: 'Toggle protection status', 31 | actionType: PageCommand.PAGE_PROTECT, 32 | desc: 'Not protected', 33 | extend: { 34 | protected: false, 35 | }, 36 | enable: true, 37 | }, 38 | ]; 39 | 40 | const GLOBAL_ACTIONS_KEY = 'global_actions'; 41 | 42 | export function getAllGlobalActions() { 43 | return browser.storage.local.get(GLOBAL_ACTIONS_KEY).then(resp => { 44 | if (resp[GLOBAL_ACTIONS_KEY]) { 45 | return resp[GLOBAL_ACTIONS_KEY]; 46 | } else { 47 | return defaultActions; 48 | } 49 | }); 50 | } 51 | 52 | export function getGlobalActions() { 53 | return getAllGlobalActions().then(resp => resp.filter(item => item.enable)); 54 | } 55 | 56 | export function setGlobalActions(jsonStr) { 57 | try { 58 | const actions = JSON.parse(jsonStr); 59 | 60 | return browser.storage.local.set({ 61 | [GLOBAL_ACTIONS_KEY]: actions, 62 | }); 63 | } catch (error) { 64 | return Promise.reject('parse error'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /extension/helper/alias.helper.ts: -------------------------------------------------------------------------------- 1 | import { browser } from 'webextension-polyfill-ts'; 2 | 3 | import util from 'common/util'; 4 | import { ResultItem, TextAliasType } from 'plugins/type'; 5 | 6 | import { getURL } from './extension.helper'; 7 | 8 | const icon = getURL('iconfont/alias.svg'); 9 | 10 | function format(list) { 11 | return list.map(item => { 12 | return { 13 | key: 'url', 14 | url: item.value, 15 | title: `${item.desc || item.value}[${item.label}]`, 16 | desc: item.lable, 17 | icon, 18 | weight: 100, 19 | }; 20 | }); 21 | } 22 | 23 | let comment; 24 | 25 | function parseLine(line) { 26 | const realLine = line.trim(); 27 | 28 | if (realLine.startsWith('##')) { 29 | comment = realLine.substring(2).trim(); 30 | 31 | return null; 32 | } else { 33 | const parts = realLine.split(/[\s]+/).slice(0, 2); 34 | const desc = comment; 35 | 36 | comment = null; 37 | 38 | return { 39 | label: parts[0], 40 | value: parts[1], 41 | desc, 42 | }; 43 | } 44 | } 45 | 46 | const STORAGE_KEY = 'text_alias'; 47 | 48 | export const TextAlias: TextAliasType = { 49 | items: null, 50 | 51 | resolveItems(text) { 52 | return text 53 | .split('\n') 54 | .filter(line => line && !line.match(/^[\s\t]+$/)) 55 | .map(parseLine) 56 | .filter(line => line && Boolean(line.label)); 57 | }, 58 | 59 | getItems() { 60 | if (this.items) { 61 | return Promise.resolve(this.items); 62 | } else { 63 | return browser.storage.sync.get(STORAGE_KEY).then(resp => { 64 | const text = resp[STORAGE_KEY]; 65 | 66 | if (text) { 67 | const items = this.resolveItems(text); 68 | 69 | this.items = items; 70 | 71 | return items; 72 | } else { 73 | return []; 74 | } 75 | }); 76 | } 77 | }, 78 | 79 | onInput(query): Promise | ResultItem[] { 80 | return this.getItems().then(items => { 81 | if (items && items.length) { 82 | return format(util.getMatches(items, query, 'label') || []); 83 | } else { 84 | return []; 85 | } 86 | }); 87 | }, 88 | }; 89 | 90 | export function getTextAlias() { 91 | return browser.storage.sync.get(STORAGE_KEY).then(resp => { 92 | return resp[STORAGE_KEY] || ''; 93 | }); 94 | } 95 | 96 | export function saveTextAlias(text) { 97 | return browser.storage.sync.set({ 98 | [STORAGE_KEY]: text, 99 | }); 100 | } 101 | -------------------------------------------------------------------------------- /extension/helper/config.helper.ts: -------------------------------------------------------------------------------- 1 | import { browser } from 'webextension-polyfill-ts'; 2 | 3 | export default { 4 | key: 'config', 5 | 6 | getData() { 7 | return browser.storage.sync.get('config').then(resp => { 8 | return resp.config; 9 | }); 10 | }, 11 | 12 | setData(config) { 13 | if (config) { 14 | return browser.storage.sync.set({ 15 | config, 16 | }); 17 | } else { 18 | return Promise.resolve('no config'); 19 | } 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /extension/helper/editor.helper.ts: -------------------------------------------------------------------------------- 1 | export function autoFormat(editor) { 2 | setTimeout(function() { 3 | editor.getAction('editor.action.formatDocument').run(); 4 | }, 300); 5 | } 6 | -------------------------------------------------------------------------------- /extension/helper/extension.helper.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export function getURL(path: string) { 4 | return chrome.extension.getURL(path); 5 | } -------------------------------------------------------------------------------- /extension/helper/i18n.helper.ts: -------------------------------------------------------------------------------- 1 | 2 | export function t(key) { 3 | return chrome.i18n.getMessage(key); 4 | } -------------------------------------------------------------------------------- /extension/helper/result.helper.ts: -------------------------------------------------------------------------------- 1 | export function createUrl({ url, title, icon, desc = '', showDesc = false }) { 2 | return { 3 | title, 4 | desc: showDesc ? desc || url : '', 5 | icon, 6 | universal: true, 7 | url, 8 | key: 'url', 9 | }; 10 | } 11 | 12 | export function createCopy({ url, title, icon, desc, showDesc }) { 13 | return { 14 | title, 15 | desc: showDesc ? desc || url : '', 16 | icon, 17 | universal: true, 18 | url, 19 | key: 'copy', 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /extension/helper/storage.helper.ts: -------------------------------------------------------------------------------- 1 | import Toast from 'toastr'; 2 | import { browser } from 'webextension-polyfill-ts'; 3 | 4 | export default class ItemsStorage { 5 | name: string; 6 | key: string; 7 | norepeat: any; 8 | appName?: any; 9 | constructor(name, key, norepeat) { 10 | this.name = name; 11 | this.key = key; 12 | this.norepeat = norepeat; 13 | } 14 | 15 | filter(item, target) { 16 | return item !== target; 17 | } 18 | 19 | removeItem(target) { 20 | return this.getItems().then(resp => { 21 | const others = resp.filter(item => { 22 | return this.filter(item, target); 23 | }); 24 | 25 | this.log('remove', target); 26 | return browser.storage.sync.set({ 27 | [this.key]: others, 28 | }); 29 | }); 30 | } 31 | 32 | isRepeat(list, target) { 33 | return list.indexOf(target) !== -1; 34 | } 35 | 36 | addItem(item) { 37 | if (item) { 38 | return this.getItems().then((items = []) => { 39 | if (this.norepeat) { 40 | if (!this.isRepeat(items, item)) { 41 | items.push(item); 42 | } else { 43 | this.log('add', item, 'cannot add repeatedly'); 44 | 45 | return Promise.reject(''); 46 | } 47 | } else { 48 | items.push(item); 49 | } 50 | 51 | this.log('add', item); 52 | 53 | return browser.storage.sync.set({ 54 | [this.key]: items, 55 | }); 56 | }); 57 | } else { 58 | return Promise.reject('no item'); 59 | } 60 | } 61 | 62 | getItems() { 63 | return browser.storage.sync.get(this.key).then(results => { 64 | return results[this.key]; 65 | }); 66 | } 67 | 68 | log(action, item, msg?) { 69 | const resultStr = msg ? `unsuccessfully: ${msg}` : 'successfully'; 70 | 71 | Toast.success( 72 | `${action} ${this.key} [${item}] ${resultStr}`, 73 | this.appName, 74 | { timeOut: 1000 }, 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /extension/helper/theme.helper.ts: -------------------------------------------------------------------------------- 1 | import { browser } from 'webextension-polyfill-ts'; 2 | 3 | import CONST from 'constant'; 4 | 5 | export default { 6 | key: CONST.STORAGE.THEMES, 7 | 8 | getData() { 9 | return browser.storage.sync.get(CONST.STORAGE.THEMES).then(resp => { 10 | return resp[CONST.STORAGE.THEMES]; 11 | }); 12 | }, 13 | 14 | setData(themes) { 15 | if (themes) { 16 | return browser.storage.sync.set({ 17 | [CONST.STORAGE.THEMES]: themes, 18 | }); 19 | } else { 20 | return Promise.resolve('no themes'); 21 | } 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /extension/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/icon.png -------------------------------------------------------------------------------- /extension/img/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/icon128.png -------------------------------------------------------------------------------- /extension/img/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/icon16.png -------------------------------------------------------------------------------- /extension/img/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/icon48.png -------------------------------------------------------------------------------- /extension/img/jenkins/aborted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/aborted.png -------------------------------------------------------------------------------- /extension/img/jenkins/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/blue.png -------------------------------------------------------------------------------- /extension/img/jenkins/health-00to19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/health-00to19.png -------------------------------------------------------------------------------- /extension/img/jenkins/health-20to39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/health-20to39.png -------------------------------------------------------------------------------- /extension/img/jenkins/health-40to59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/health-40to59.png -------------------------------------------------------------------------------- /extension/img/jenkins/health-60to79.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/health-60to79.png -------------------------------------------------------------------------------- /extension/img/jenkins/health-80plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/health-80plus.png -------------------------------------------------------------------------------- /extension/img/jenkins/nobuilt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/nobuilt.png -------------------------------------------------------------------------------- /extension/img/jenkins/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/jenkins/red.png -------------------------------------------------------------------------------- /extension/img/wordcard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solobat/Steward/bf207462ea597cc9af2db18c8be57eed77175dc7/extension/img/wordcard.png -------------------------------------------------------------------------------- /extension/info/changelog.ts: -------------------------------------------------------------------------------- 1 | const langZh = [ 2 | { 3 | version: 'v4.1.1', 4 | detail: '修复: 计算结果不能复制的问题;外观: 新增各种 height 的可配置。' 5 | }, 6 | { 7 | version: 'v4.1.0', 8 | detail: '整体重构;新增plugin/组件的参数支持;新增命令框空查询;支持plugin级别的使用频次排序;移除无效的plugins。' 9 | }, 10 | { 11 | version: 'v4.0.6', 12 | detail: '移除一些失效的内置 chrome 页面,以及小优化', 13 | }, 14 | { 15 | version: 'v4.0.5', 16 | detail: '优化及 Bug 修复', 17 | }, 18 | { 19 | version: 'v4.0.4', 20 | detail: '优化及 Bug 修复', 21 | }, 22 | { 23 | version: 'v4.0.3', 24 | detail: 'bugfix', 25 | }, 26 | { 27 | version: 'v4.0.2', 28 | detail: 29 | '组件支持快捷键显示/隐藏;component plugin 提供 show/hide 命令启动和禁用组件', 30 | }, 31 | { 32 | version: 'v4.0.1', 33 | detail: '搜索结果按使用次数排序;newtab layout 优化; 组件源切换', 34 | }, 35 | { 36 | version: 'v4.0.0', 37 | detail: 'Newtab 组件化,可定制; 设置页重构', 38 | }, 39 | ]; 40 | 41 | const langEn = [ 42 | { 43 | version: 'v4.1.1', 44 | detail: 'fix: calc result copy issue; appearance: height of box configurable', 45 | }, 46 | { 47 | version: 'v4.1.0', 48 | detail: 'Refactor; Plugin/Component args supportted; Query onEmpty setting; Plugin level results sorted; Remove some invalid plugins.' 49 | }, 50 | { 51 | version: 'v4.0.6', 52 | detail: 'remove some invalid chrome pages && optimization', 53 | }, 54 | { 55 | version: 'v4.0.5', 56 | detail: 'optimization && bugfix', 57 | }, 58 | { 59 | version: 'v4.0.4', 60 | detail: 'optimization && bugfix', 61 | }, 62 | { 63 | version: 'v4.0.3', 64 | detail: 'bugfix', 65 | }, 66 | { 67 | version: 'v4.0.2', 68 | detail: 69 | 'Use shortcut keys to show components; Provide show / hide command to enable and disable components', 70 | }, 71 | { 72 | version: 'v4.0.1', 73 | detail: 74 | 'Sort search results by number of uses; newtab layout optimization; component source switching', 75 | }, 76 | { 77 | version: 'v4.0.0', 78 | detail: 'Component Newtab page, customizable; refactor the settings page', 79 | }, 80 | ]; 81 | 82 | let results; 83 | 84 | if (chrome.i18n.getUILanguage().indexOf('zh') > -1) { 85 | results = langZh; 86 | } else { 87 | results = langEn; 88 | } 89 | 90 | export default results; 91 | -------------------------------------------------------------------------------- /extension/info/help.ts: -------------------------------------------------------------------------------- 1 | 2 | const langZh = ` 3 | 帮助文档 4 | 论坛 5 | Telegram 6 |
7 | QQ群: 575397892 8 |
9 |
10 | 微信公众号 11 | `; 12 | 13 | const langEn = ` 14 | Documentation
15 | 16 |
17 | Please try to upgrade the latest version of the browser, to avoid some of the features can not be used.
18 | If you have any suggestions / problems in the process of using it, you can go here,or join the Telegram channel. 19 | `; 20 | 21 | let results; 22 | 23 | if (chrome.i18n.getUILanguage().indexOf('zh') > -1) { 24 | results = langZh; 25 | } else { 26 | results = langEn; 27 | } 28 | 29 | export const helpInfo = results; 30 | -------------------------------------------------------------------------------- /extension/info/i18n.ts: -------------------------------------------------------------------------------- 1 | import { t } from "helper/i18n.helper"; 2 | 3 | export const settings = { 4 | notion: { 5 | workflow: t('settings_notion_workflow'), 6 | website: t('settings_notion_website'), 7 | }, 8 | fields: { 9 | title: t('settings_fields_title'), 10 | description: t('settings_fields_description'), 11 | content: t('settings_fields_content'), 12 | host: t('settings_fields_host'), 13 | siteicon: t('settings_fields_siteicon'), 14 | paths: t('settings_fields_paths'), 15 | navigations: t('settings_fields_navigations'), 16 | outlinescope: t('settings_fields_outlinescope'), 17 | anchors: t('settings_fields_anchors'), 18 | disable: t('settings_fields_disable'), 19 | enable: t('settings_fields_enable'), 20 | show: t('settings_fields_show'), 21 | showByDefault: t('settings_fields_showbydefault'), 22 | }, 23 | tabs: { 24 | general: t('settings_tabs_general'), 25 | plugins: t('settings_tabs_plugins'), 26 | workflows: t('settings_tabs_workflows'), 27 | websites: t('settings_tabs_websites'), 28 | wallpapers: t('settings_tabs_wallpapers'), 29 | newtabcomponents: t('settings_tabs_newtabcomponents'), 30 | appearance: t('settings_tabs_appearance'), 31 | advanced: t('settings_tabs_advanced'), 32 | help: t('settings_tabs_help'), 33 | update: t('settings_tabs_update'), 34 | }, 35 | blocks: { 36 | commandsplugins: t('settings_blocks_commandsplugins'), 37 | operationinteraction: t('settings_blocks_operationinteraction'), 38 | websitesconfiguration: t('settings_blocks_websitesconfiguration'), 39 | newtab: t('settings_blocks_newtab'), 40 | performance: t('settings_blocks_performance'), 41 | shortcutconfiguration: t('settings_blocks_shortcutconfiguration'), 42 | websitebaseinfo: t('settings_blocks_websitebaseinfo'), 43 | websitenav: t('settings_blocks_websitenav'), 44 | inpagenav: t('settings_blocks_inpagenav'), 45 | exportimport: t('settings_blocks_exportimport'), 46 | socialshareconfig: t('settings_blocks_socialshareconfig'), 47 | plugineditor: t('settings_blocks_plugineditor'), 48 | }, 49 | actions: { 50 | save: t('settings_actions_save'), 51 | delete: t('settings_actions_delete'), 52 | newworkflow: t('settings_actions_newworkflow'), 53 | newwebsite: t('settings_actions_newwebsite'), 54 | applysave: t('settings_actions_applysave'), 55 | reset: t('settings_actions_reset'), 56 | export: t('settings_actions_export'), 57 | import: t('settings_actions_import'), 58 | downloadcrx: t('settings_actions_downloadcrx'), 59 | }, 60 | }; 61 | -------------------------------------------------------------------------------- /extension/main/Steward.ts: -------------------------------------------------------------------------------- 1 | import Axios from 'axios'; 2 | import md5 from 'blueimp-md5'; 3 | import dayjs from 'dayjs'; 4 | import $ from 'jquery'; 5 | import Toast from 'toastr'; 6 | import _ from 'underscore'; 7 | import { browser } from 'webextension-polyfill-ts'; 8 | 9 | import { StewardApp } from 'common/type'; 10 | import util from 'common/util'; 11 | import CONST from 'constant'; 12 | import PromisifyStorage from 'utils/storage'; 13 | 14 | function installGlobalSteward() { 15 | window.__Steward__ = window.stewardApp = getGlobalStewardAPI(); 16 | } 17 | 18 | export function getGlobalStewardAPI() { 19 | return { 20 | chrome: window.chrome, 21 | browser, 22 | Toast, 23 | md5, 24 | axios: Axios, 25 | dayjs: dayjs, 26 | $, 27 | storage: PromisifyStorage, 28 | 29 | state: { 30 | background: false, 31 | key: '', 32 | stage: '', 33 | str: '', 34 | cmd: '', 35 | query: '', 36 | delay: 0, 37 | lastcmd: '', 38 | command: null, 39 | workflowStack: [], 40 | keyStatus: { 41 | shiftKey: false, 42 | ctrlKey: false, 43 | metaKey: false, 44 | altKey: false, 45 | }, 46 | }, 47 | 48 | util, 49 | constant: CONST, 50 | } as StewardApp; 51 | } 52 | 53 | const Steward = new Proxy({} as StewardApp, { 54 | get(_, path) { 55 | if (!window.__Steward__) { 56 | installGlobalSteward(); 57 | } 58 | 59 | return window.__Steward__[path]; 60 | }, 61 | set(_, path, value) { 62 | if (!window.__Steward__) { 63 | installGlobalSteward(); 64 | } 65 | window.__Steward__[path] = value; 66 | 67 | return true 68 | } 69 | }); 70 | 71 | export default Steward; 72 | -------------------------------------------------------------------------------- /extension/main/cache.ts: -------------------------------------------------------------------------------- 1 | import { StewardCache } from 'common/type' 2 | 3 | function initCache() { 4 | window.__StewardCache__ = {} 5 | } 6 | 7 | const stewardCache = new Proxy({}, { 8 | get(_, path: keyof StewardCache) { 9 | if (!window.__StewardCache__) { 10 | initCache() 11 | } 12 | return window.__StewardCache__[path] 13 | }, 14 | set(_, path, value) { 15 | if (!window.__StewardCache__) { 16 | initCache() 17 | } 18 | 19 | window.__StewardCache__[path] = value; 20 | 21 | return true; 22 | } 23 | }) 24 | 25 | export default stewardCache -------------------------------------------------------------------------------- /extension/main/type.ts: -------------------------------------------------------------------------------- 1 | import { PluginCommand, StewardApp } from "common/type"; 2 | import { KeyStatus } from "plugins/type"; 3 | 4 | export interface AppState { 5 | background: boolean; 6 | key: string; 7 | stage: string; 8 | str: string; 9 | cmd: string; 10 | query: string; 11 | delay: number; 12 | lastcmd: string; 13 | command: PluginCommand | null; 14 | workflowStack: string[]; 15 | keyStatus: Partial; 16 | searchTimer?: number; 17 | } 18 | 19 | export interface CommandResultItem { 20 | key: string; 21 | id: string; 22 | icon: string; 23 | title: string; 24 | desc: string; 25 | weight: number; 26 | } 27 | 28 | export interface StewardReadyEventDetail { 29 | app: StewardApp, 30 | } 31 | 32 | export type StewardReadyEvent = CustomEvent 33 | 34 | export type WALLPAPER_ACTION_TYPE = 'save' | 'remove' 35 | export interface WALLPAPER_ACTION { 36 | action: WALLPAPER_ACTION_TYPE; 37 | msg: string 38 | } -------------------------------------------------------------------------------- /extension/pages/background/background.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /extension/pages/content/content.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | content page 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /extension/pages/content/content.scss: -------------------------------------------------------------------------------- 1 | 2 | .steward-main { 3 | position: fixed; 4 | z-index: 2222222222; 5 | top: 60px; 6 | left: 50%; 7 | width: 530px; 8 | margin-left: -255px; 9 | 10 | &.newtab { 11 | width: 100%; 12 | height: 100%; 13 | left: 0; 14 | top: 0; 15 | margin-left: 0; 16 | } 17 | } 18 | 19 | .base0E { 20 | color: #f2777a; 21 | } -------------------------------------------------------------------------------- /extension/pages/login/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file login for auth callback 3 | * @description auth validation callback 4 | * @author tomasy 5 | * @email solopea@gmail.com 6 | */ 7 | 8 | import Auth from 'common/auth'; 9 | import conf from 'conf/pocket_conf'; 10 | 11 | console.log('hello login.js....'); 12 | 13 | const auth = new Auth(conf); 14 | 15 | function handler(results) { 16 | const ret = results || {}; 17 | 18 | return ret; 19 | } 20 | 21 | auth.getAccessToken(handler, function() { 22 | console.log('login success!....'); 23 | window.close(); 24 | }); 25 | -------------------------------------------------------------------------------- /extension/pages/login/login.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Login Page 7 | 8 | 9 | 10 |

Hello Steward

11 | 12 | 13 | -------------------------------------------------------------------------------- /extension/pages/options/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import ElementUI from 'element-ui'; 3 | import App from './App.vue'; 4 | import 'element-ui/lib/theme-default/index.css'; 5 | import 'bootstrap/dist/css/bootstrap.min.css' 6 | import 'spectre.css/dist/spectre-icons.min.css' 7 | import util from 'common/util'; 8 | import * as i18n from 'info/i18n'; 9 | import CONST from 'constant/index'; 10 | import router from '@/pages/options/router'; 11 | import { t } from 'helper/i18n.helper'; 12 | 13 | const manifest = chrome.runtime.getManifest(); 14 | const version = manifest.version; 15 | 16 | Vue.use(ElementUI); 17 | 18 | const getConfig = util.getData('getConfig'); 19 | 20 | function init() { 21 | Promise.all([getConfig()]).then(([config]) => { 22 | const tips = CONST.I18N.TIPS; 23 | 24 | config.lastVersion = config.version || version; 25 | // only used for options page 26 | window.optionsPage = { 27 | config, 28 | }; 29 | 30 | const i18nTexts = getI18nTexts({ general: config.general, tips }); 31 | 32 | i18nTexts.ui = i18n; 33 | 34 | render(config, i18nTexts); 35 | }); 36 | } 37 | 38 | function getI18nTexts(obj, prefix) { 39 | try { 40 | if (typeof obj === 'object' && !(obj instanceof Array)) { 41 | const ret = {}; 42 | 43 | for (const key in obj) { 44 | const nextPrefix = prefix ? `${prefix}_${key}` : key; 45 | 46 | ret[key] = getI18nTexts(obj[key], nextPrefix); 47 | } 48 | return ret; 49 | } else { 50 | return t(prefix); 51 | } 52 | } catch (e) { 53 | console.log(e); 54 | return {}; 55 | } 56 | } 57 | 58 | function render({ general, plugins }, i18nTexts) { 59 | new Vue({ 60 | el: '#app', 61 | data: { 62 | config: { 63 | general, 64 | plugins, 65 | version, 66 | }, 67 | i18nTexts, 68 | }, 69 | router, 70 | components: { App }, 71 | template: '', 72 | }); 73 | } 74 | 75 | init(); 76 | -------------------------------------------------------------------------------- /extension/pages/options/options.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Preference 7 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /extension/pages/options/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import General from '@/pages/options/views/General.vue' 4 | import Plugins from '@/pages/options/views/Plugins.vue' 5 | import Workflows from '@/pages/options/views/Workflows.vue' 6 | import Websites from '@/pages/options/views/Websites.vue' 7 | import Newtabcomponents from '@/pages/options/views/Newtabcomponents.vue' 8 | import Wallpapers from '@/pages/options/views/Wallpapers.vue' 9 | import Appearance from '@/pages/options/views/Appearance.vue' 10 | import Advanced from '@/pages/options/views/Advanced.vue' 11 | import Help from '@/pages/options/views/Help.vue' 12 | import Update from '@/pages/options/views/Update.vue' 13 | 14 | Vue.use(VueRouter) 15 | 16 | const routes = [ 17 | { 18 | path: '/', 19 | name: 'General', 20 | component: General, 21 | meta: { 22 | } 23 | }, 24 | { 25 | path: '/plugins', 26 | name: 'Plugins', 27 | component: Plugins, 28 | meta: { 29 | } 30 | }, 31 | { 32 | path: '/workflows', 33 | name: 'Workflows', 34 | component: Workflows, 35 | meta: { 36 | } 37 | }, 38 | { 39 | path: '/websites', 40 | name: 'Websites', 41 | component: Websites, 42 | meta: { 43 | } 44 | }, 45 | { 46 | path: '/newtabcomponents', 47 | name: 'Newtabcomponents', 48 | component: Newtabcomponents, 49 | meta: { 50 | } 51 | }, 52 | { 53 | path: '/wallpapers', 54 | name: 'Wallpapers', 55 | component: Wallpapers, 56 | meta: { 57 | } 58 | }, 59 | { 60 | path: '/appearance', 61 | name: 'Appearance', 62 | component: Appearance, 63 | meta: { 64 | } 65 | }, 66 | { 67 | path: '/advanced', 68 | name: 'Advanced', 69 | component: Advanced, 70 | meta: { 71 | } 72 | }, 73 | { 74 | path: '/help', 75 | name: 'Help', 76 | component: Help, 77 | meta: { 78 | } 79 | }, 80 | { 81 | path: '/update', 82 | name: 'Update', 83 | component: Update, 84 | meta: { 85 | } 86 | }, 87 | { path: '*', redirect: '/' } 88 | ] 89 | 90 | const router = new VueRouter({ 91 | mode: 'hash', 92 | routes 93 | }) 94 | 95 | export default router 96 | -------------------------------------------------------------------------------- /extension/pages/options/views/Help.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | -------------------------------------------------------------------------------- /extension/pages/options/views/Update.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 39 | 40 | -------------------------------------------------------------------------------- /extension/pages/popup/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 34 | 35 | 82 | 83 | -------------------------------------------------------------------------------- /extension/pages/popup/popup.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | popup 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /extension/pages/steward/index.js: -------------------------------------------------------------------------------- 1 | import { initConfig, globalApi, installApp } from '../../main/main'; 2 | import Vue from 'vue'; 3 | import ElementUI from 'element-ui'; 4 | import 'element-ui/lib/theme-default/index.css'; 5 | import App from './App.vue'; 6 | import dayjs from 'dayjs'; 7 | import axios from 'axios'; 8 | import { Loading } from 'element-ui'; 9 | import { registerComponents } from 'helper/component.helper'; 10 | 11 | Vue.use(ElementUI); 12 | Vue.config.productionTip = false; 13 | Vue.config.devtools = true; 14 | Vue.prototype.$dayjs = dayjs; 15 | Vue.prototype.$http = axios; 16 | Vue.use(Loading.directive); 17 | Vue.prototype.$axios = axios; 18 | Vue.prototype.$notify = function notify(title, body) { 19 | Notification.requestPermission(function(status) { 20 | if (status === 'granted') { 21 | new Notification(title, { body }); 22 | } 23 | }); 24 | }; 25 | 26 | const mode = 'newTab'; 27 | 28 | initConfig(mode, false).then(config => { 29 | const appData = { mode, data: {}, config }; 30 | globalApi(appData); 31 | registerComponents(Vue, config.components); 32 | 33 | const app = new Vue({ 34 | el: '#app', 35 | data: { 36 | config, 37 | }, 38 | components: { App }, 39 | template: '', 40 | }); 41 | 42 | installApp(app); 43 | }); 44 | -------------------------------------------------------------------------------- /extension/pages/steward/steward.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | New Tab 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /extension/pages/urlblock/index.ts: -------------------------------------------------------------------------------- 1 | import PluginHelper from 'helper/plugin.helper'; 2 | 3 | const pluginHelper = new PluginHelper(); 4 | 5 | chrome.runtime.sendMessage( 6 | { 7 | action: 'getData', 8 | }, 9 | resp => { 10 | pluginHelper.init(resp.data.blockedUrls); 11 | }, 12 | ); 13 | -------------------------------------------------------------------------------- /extension/pages/urlblock/urlblock.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | url block message 6 | 12 | 13 | 14 |

This page has been blocked by yourself!

15 | 16 | 17 | -------------------------------------------------------------------------------- /extension/plugins/browser/del.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description delete extensions / apps by del command 3 | * @author tomasy 4 | * @mail solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { getURL } from 'helper/extension.helper'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { Command, Plugin } from 'plugins/type'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, util } = Steward; 14 | 15 | const version = 2; 16 | const name = 'deleteExtension'; 17 | const key = 'del'; 18 | const type = 'keyword'; 19 | const icon = getURL('iconfont/del.svg'); 20 | const title = t(`${name}_title`); 21 | const subtitle = t(`${name}_subtitle`); 22 | const commands: Command[] = [ 23 | { 24 | key, 25 | type, 26 | title, 27 | subtitle, 28 | icon, 29 | editable: true, 30 | }, 31 | ]; 32 | 33 | function uninstall(id, cb) { 34 | Steward.chrome.management.uninstall(id, function(...args) { 35 | Reflect.apply(cb, null, args); 36 | }); 37 | } 38 | 39 | // get all 40 | function getExtensions(query, enabled, callback) { 41 | chrome.management.getAll(function(extList) { 42 | const matchExts = extList.filter(function(ext) { 43 | return util.matchText(query, ext.name); 44 | }); 45 | 46 | callback(matchExts); 47 | }); 48 | } 49 | 50 | function dataFormat(rawList) { 51 | return rawList.map(function(item) { 52 | const url = 53 | item.icons instanceof Array 54 | ? item.icons[item.icons.length - 1].url 55 | : ''; 56 | const isWarn = item.installType === 'development'; 57 | return { 58 | key, 59 | id: item.id, 60 | icon: url, 61 | title: item.name, 62 | desc: item.description, 63 | isWarn: isWarn, 64 | }; 65 | }); 66 | } 67 | 68 | function onInput(query) { 69 | return new Promise(resolve => { 70 | getExtensions(query.toLowerCase(), false, function(matchExts) { 71 | resolve(dataFormat(matchExts)); 72 | }); 73 | }); 74 | } 75 | 76 | function onEnter(item) { 77 | uninstall(item.id, () => { 78 | Steward.app.refresh(); 79 | }); 80 | } 81 | return { 82 | version, 83 | name: 'Delete Extension', 84 | category: 'browser', 85 | icon, 86 | title, 87 | commands, 88 | onInput, 89 | onEnter, 90 | canDisabled: false, 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /extension/plugins/browser/on.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description enable extensions/apps 3 | * @author tomasy 4 | * @email solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { getURL } from 'helper/extension.helper'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { Command, Plugin, Type } from 'plugins/type'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, util } = Steward; 14 | 15 | const version = 2; 16 | const name = 'onExtension'; 17 | const key = 'on'; 18 | const type: Type = 'keyword'; 19 | const icon = getURL('iconfont/on.svg'); 20 | const title = t(`${name}_title`); 21 | const subtitle = t(`${name}_subtitle`); 22 | const commands: Command[] = [ 23 | { 24 | key, 25 | type, 26 | title, 27 | subtitle, 28 | icon, 29 | editable: true, 30 | }, 31 | ]; 32 | 33 | function setEnabled(id, enabled) { 34 | chrome.management.setEnabled(id, enabled, function() {}); 35 | } 36 | 37 | function getExtensions(query, enabled, callback) { 38 | chrome.management.getAll(function(extList) { 39 | const matchExts = extList.filter(function(ext) { 40 | return ( 41 | ext.type === 'extension' && 42 | util.matchText(query, ext.name) && 43 | ext.enabled === enabled 44 | ); 45 | }); 46 | 47 | callback(matchExts); 48 | }); 49 | } 50 | 51 | function dataFormat(rawList) { 52 | return rawList.map(function(item) { 53 | const url = 54 | item.icons instanceof Array 55 | ? item.icons[item.icons.length - 1].url 56 | : ''; 57 | const isWarn = item.installType === 'development'; 58 | 59 | return { 60 | key, 61 | id: item.id, 62 | icon: url, 63 | title: item.name, 64 | desc: item.description, 65 | isWarn, 66 | }; 67 | }); 68 | } 69 | 70 | function onInput(query) { 71 | return new Promise(resolve => { 72 | getExtensions(query.toLowerCase(), false, function(matchExts) { 73 | resolve(dataFormat(matchExts)); 74 | }); 75 | }); 76 | } 77 | 78 | function onEnter(item) { 79 | if (item && item.id) { 80 | setEnabled(item.id, true); 81 | window.slogs.push(`Enable: ${item.title}`); 82 | Steward.app.refresh(); 83 | } 84 | } 85 | 86 | return { 87 | version, 88 | name: 'Enable Extension', 89 | category: 'browser', 90 | icon, 91 | title, 92 | commands, 93 | onInput, 94 | onEnter, 95 | canDisabled: false, 96 | }; 97 | } 98 | -------------------------------------------------------------------------------- /extension/plugins/browser/run.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description run app 3 | * @author tomasy 4 | * @email solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { getURL } from 'helper/extension.helper'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { Command, Plugin } from 'plugins/type'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, util } = Steward; 14 | 15 | const version = 2; 16 | const name = 'runapp'; 17 | const key = 'run'; 18 | const type = 'keyword'; 19 | const icon = getURL('iconfont/app.svg'); 20 | const title = t(`${name}_title`); 21 | const subtitle = t(`${name}_subtitle`); 22 | const commands: Command[] = [ 23 | { 24 | key, 25 | type, 26 | title, 27 | subtitle, 28 | icon, 29 | editable: true, 30 | }, 31 | ]; 32 | 33 | function getExtensions(query, callback) { 34 | chrome.management.getAll(function(extList) { 35 | const data = extList.filter(function(ext) { 36 | return util.matchText(query, ext.name) && ext.isApp; 37 | }); 38 | 39 | callback(data); 40 | }); 41 | } 42 | 43 | function dataFormat(rawList) { 44 | return rawList.map(function(item) { 45 | const url = item.icons instanceof Array ? item.icons[0].url : ''; 46 | const isWarn = item.installType === 'development'; 47 | 48 | return { 49 | key, 50 | id: item.id, 51 | icon: url, 52 | title: item.name, 53 | desc: item.description, 54 | isWarn, 55 | }; 56 | }); 57 | } 58 | 59 | function onInput(query) { 60 | return new Promise(resolve => { 61 | getExtensions(query.toLowerCase(), function(data) { 62 | resolve(dataFormat(data)); 63 | }); 64 | }); 65 | } 66 | 67 | function launch(id) { 68 | chrome.management.setEnabled(id, true, function() { 69 | chrome.management.launchApp(id, function() {}); 70 | }); 71 | } 72 | 73 | function onEnter(item) { 74 | const { id } = item; 75 | 76 | launch(id); 77 | Steward.app.refresh(); 78 | } 79 | 80 | return { 81 | version, 82 | name: 'Run App', 83 | category: 'browser', 84 | icon, 85 | title, 86 | commands, 87 | onInput, 88 | onEnter, 89 | canDisabled: false, 90 | }; 91 | } 92 | -------------------------------------------------------------------------------- /extension/plugins/browser/set.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description open extension's option page 3 | * @author tomasy 4 | * @mail solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { getURL } from 'helper/extension.helper'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { Command, Plugin } from 'plugins/type'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, util } = Steward; 14 | 15 | const version = 2; 16 | const name = 'setOption'; 17 | const key = 'set'; 18 | const type = 'keyword'; 19 | const icon = getURL('iconfont/set.svg'); 20 | const title = t(`${name}_title`); 21 | const subtitle = t(`${name}_subtitle`); 22 | const commands: Command[] = [ 23 | { 24 | key, 25 | type, 26 | title, 27 | subtitle, 28 | icon, 29 | editable: true, 30 | }, 31 | ]; 32 | 33 | function openOptionPage(item, keyStatus) { 34 | const url = item.url; 35 | 36 | if (!url) { 37 | return; 38 | } 39 | 40 | util.createTab({ url: url }, keyStatus); 41 | } 42 | 43 | // get all 44 | function getExtensions(query, enabled, callback) { 45 | chrome.management.getAll(function(extList) { 46 | const matchExts = extList.filter(function(ext) { 47 | return ( 48 | !ext.isApp && 49 | ext.enabled === enabled && 50 | util.matchText(query, ext.name) 51 | ); 52 | }); 53 | 54 | callback(matchExts); 55 | }); 56 | } 57 | 58 | function dataFormat(rawList) { 59 | return rawList.map(function(item) { 60 | const url = 61 | item.icons instanceof Array 62 | ? item.icons[item.icons.length - 1].url 63 | : ''; 64 | const isWarn = item.installType === 'development'; 65 | 66 | return { 67 | key, 68 | id: item.id, 69 | icon: url, 70 | title: item.name, 71 | url: item.optionsUrl, 72 | desc: item.description, 73 | isWarn, 74 | }; 75 | }); 76 | } 77 | function onInput(query) { 78 | return new Promise(resolve => { 79 | getExtensions(query.toLowerCase(), true, function(matchExts) { 80 | resolve(dataFormat(matchExts)); 81 | }); 82 | }); 83 | } 84 | 85 | function onEnter(item, command, query, keyStatus) { 86 | openOptionPage(item, keyStatus); 87 | } 88 | 89 | return { 90 | version, 91 | name: 'Set Extension', 92 | category: 'browser', 93 | icon, 94 | title, 95 | commands, 96 | onInput, 97 | onEnter, 98 | canDisabled: false, 99 | }; 100 | } 101 | -------------------------------------------------------------------------------- /extension/plugins/browser/topsites.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description list the most visit websites 3 | * @author tomasy 4 | * @email solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { getURL } from 'helper/extension.helper'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { Command, Plugin } from 'plugins/type'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, util } = Steward; 14 | 15 | const version = 4; 16 | const name = 'topsites'; 17 | const key = 'site'; 18 | const type = 'keyword'; 19 | const icon = getURL('iconfont/topsites.svg'); 20 | const title = t(`${name}_title`); 21 | const subtitle = t(`${name}_subtitle`); 22 | const commands: Command[] = [ 23 | { 24 | key, 25 | type, 26 | title, 27 | subtitle, 28 | icon, 29 | allowBatch: true, 30 | shiftKey: true, 31 | editable: true, 32 | }, 33 | ]; 34 | 35 | function onInput() { 36 | return new Promise(resolve => { 37 | chrome.topSites.get(sites => { 38 | const arr = []; 39 | const wrapDesc = util.wrapWithMaxNumIfNeeded('url'); 40 | let i; 41 | 42 | for (i in sites) { 43 | const item = sites[i]; 44 | const desc = wrapDesc(item, i); 45 | arr.push({ 46 | key, 47 | id: item.url, 48 | icon: icon, 49 | url: item.url, 50 | title: item.title, 51 | desc, 52 | isWarn: false, 53 | }); 54 | } 55 | 56 | resolve(arr); 57 | }); 58 | }); 59 | } 60 | 61 | function onEnter(item, command, query, { shiftKey }, list) { 62 | util.batchExecutionIfNeeded(shiftKey, util.tabCreateExecs, [list, item]); 63 | return Promise.resolve(''); 64 | } 65 | 66 | return { 67 | version, 68 | name: 'Top Sites', 69 | category: 'browser', 70 | icon, 71 | title, 72 | commands, 73 | onInput, 74 | onEnter, 75 | canDisabled: false, 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /extension/plugins/other/calculate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description calculate 3 | * @author tomasy 4 | * @mail solopea@gmail.com 5 | */ 6 | 7 | import mathexp from 'math-expression-evaluator'; 8 | 9 | import { Command, Plugin } from 'plugins/type'; 10 | import { StewardApp } from 'common/type'; 11 | import { t } from 'helper/i18n.helper'; 12 | import { getURL } from 'helper/extension.helper'; 13 | 14 | export default function(Steward: StewardApp): Plugin { 15 | const { chrome, util } = Steward; 16 | 17 | const name = 'calculate'; 18 | const version = 4; 19 | const type = 'always'; 20 | const key = 'calc'; 21 | const icon = getURL('iconfont/calc.svg'); 22 | const title = t(`${name}_title`); 23 | const subtitle = t(`${name}_subtitle`); 24 | const commands: Command[] = [ 25 | { 26 | key, 27 | type, 28 | title, 29 | subtitle, 30 | icon, 31 | editable: false, 32 | }, 33 | ]; 34 | 35 | function onInput(query) { 36 | let data = []; 37 | if (query.startsWith('calc ') && query) { 38 | return; 39 | } 40 | try { 41 | const result = mathexp.eval(Steward.state.str); 42 | data = [ 43 | { 44 | key: 'copy', 45 | icon: icon, 46 | title: result, 47 | desc: subtitle, 48 | content: result, 49 | universal: true 50 | }, 51 | ]; 52 | } catch (e) { 53 | data = null; 54 | } 55 | 56 | return Promise.resolve(data); 57 | } 58 | 59 | function onEnter(item) { 60 | const text = item.title; 61 | 62 | util.copyToClipboard(text, true); 63 | 64 | return Promise.resolve(false); 65 | } 66 | 67 | return { 68 | version, 69 | name: 'Calculator', 70 | category: 'other', 71 | icon, 72 | title, 73 | commands, 74 | onInput, 75 | onEnter, 76 | canDisabled: false, 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /extension/plugins/other/openurl.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description open url in browser 3 | * @author tomasy 4 | * @mail solopea@gmail.com 5 | */ 6 | 7 | import urlRegex from 'url-regex'; 8 | 9 | import { Command, Plugin } from 'plugins/type'; 10 | import { StewardApp } from 'common/type'; 11 | import { t } from 'helper/i18n.helper'; 12 | import { getURL } from 'helper/extension.helper'; 13 | 14 | export default function(Steward: StewardApp): Plugin { 15 | const { chrome, util } = Steward; 16 | 17 | const version = 3; 18 | const name = 'openurl'; 19 | const key = 'open'; 20 | const type = 'regexp'; 21 | const icon = getURL('iconfont/openurl.svg'); 22 | const title = t(`${name}_title`); 23 | const subtitle = t(`${name}_subtitle`); 24 | const regExp: RegExp = urlRegex({ exact: true, strict: false }); 25 | 26 | regExp.formatter = (query: string) => query.replace(/。/g, '.') 27 | 28 | const commands: Command[] = [ 29 | { 30 | key, 31 | title, 32 | type, 33 | subtitle, 34 | icon, 35 | editable: false, 36 | regExp, 37 | }, 38 | ]; 39 | 40 | function onInput(url) { 41 | const data = [ 42 | { 43 | key: 'url', 44 | id: name, 45 | icon, 46 | title: regExp.formatter(url), 47 | desc: subtitle, 48 | url, 49 | }, 50 | ]; 51 | 52 | return data; 53 | } 54 | 55 | function onEnter(item, command, query, keyStatus) { 56 | const { url } = item; 57 | let theurl = url; 58 | 59 | if (!/^https?/.test(url)) { 60 | theurl = `http://${url}`; 61 | } 62 | util.createTab({ url: theurl }, keyStatus); 63 | } 64 | 65 | return { 66 | version, 67 | name: 'Open Url', 68 | category: 'other', 69 | icon, 70 | title, 71 | onInput, 72 | onEnter, 73 | commands, 74 | canDisabled: false, 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /extension/plugins/steward/about.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description about steward 3 | * @author tomasy 4 | * @email solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { getAboutLinks, getUpLinks } from 'info/links'; 9 | import { Plugin } from 'plugins/type'; 10 | import { t } from 'helper/i18n.helper'; 11 | import { getURL } from 'helper/extension.helper'; 12 | 13 | export default function(Steward: StewardApp): Plugin { 14 | const { chrome, util } = Steward; 15 | 16 | const version = 1; 17 | const name = 'about'; 18 | const keys = [ 19 | { key: 'about', shiftKey: true, allowBatch: true, editable: false }, 20 | { key: 'up', shiftKey: true, allowBatch: true, editable: false }, 21 | ]; 22 | const type = 'keyword'; 23 | const icon = getURL('img/icon.png'); 24 | const title = t(`${name}_title`); 25 | const commands = util.genCommands(name, icon, keys, type); 26 | const lang = chrome.i18n.getUILanguage().indexOf('zh') > -1 ? 'zh' : 'en'; 27 | const aboutLinks = getAboutLinks(lang); 28 | const upLinks = getUpLinks(lang); 29 | 30 | function dataFormat(list, command?: any) { 31 | const wrapDesc = util.wrapWithMaxNumIfNeeded('desc'); 32 | 33 | return list.map((item, i) => { 34 | const desc = wrapDesc(item, i); 35 | return { 36 | key: 'plugins', 37 | title: item.title, 38 | icon: item.icon || icon, 39 | desc, 40 | url: item.url, 41 | }; 42 | }); 43 | } 44 | 45 | function onInput(query, command) { 46 | return new Promise(resolve => { 47 | if (command.orkey === 'about') { 48 | resolve(dataFormat(aboutLinks, command)); 49 | } else { 50 | resolve(dataFormat(upLinks, command)); 51 | } 52 | }); 53 | } 54 | 55 | function onEnter(item, command, query, { shiftKey }, list) { 56 | util.batchExecutionIfNeeded(shiftKey, util.tabCreateExecs, [list, item]); 57 | } 58 | 59 | return { 60 | version, 61 | name: 'About Steward', 62 | category: 'steward', 63 | icon, 64 | title, 65 | commands, 66 | onInput, 67 | onEnter, 68 | canDisabled: false, 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /extension/plugins/steward/component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description components manager 3 | * @author tomasy 4 | * @email solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { componentHelper, getComponentsConfig } from 'helper/component.helper'; 9 | import { Plugin } from 'plugins/type'; 10 | import { t } from 'helper/i18n.helper'; 11 | import { getURL } from 'helper/extension.helper'; 12 | 13 | export default function(Steward: StewardApp): Plugin { 14 | const { chrome, util } = Steward; 15 | 16 | const version = 1; 17 | const name = 'component'; 18 | const keys = [{ key: 'show' }, { key: 'hide' }]; 19 | const type = 'keyword'; 20 | const icon = getURL('img/icon.png'); 21 | const title = t(`${name}_title`); 22 | const commands = util.genCommands(name, icon, keys, type); 23 | 24 | function dataFormatter(item) { 25 | const { title, subtitle, icon: theIcon, id } = item.meta; 26 | return { 27 | key: 'component', 28 | title, 29 | desc: subtitle, 30 | icon: theIcon || icon, 31 | id, 32 | }; 33 | } 34 | 35 | function onInput(key, command) { 36 | const isShow = command.orkey === 'show'; 37 | 38 | return getComponentsConfig().then(list => { 39 | const items = list 40 | .filter(item => item.show === !isShow) 41 | .map(dataFormatter); 42 | const matched = key ? util.getMatches(items, key, 'title') : items; 43 | 44 | return matched; 45 | }); 46 | } 47 | 48 | function onEnter(item, command) { 49 | const { orkey } = command; 50 | const isShow = orkey === 'show'; 51 | const { id } = item; 52 | 53 | return componentHelper 54 | .update({ 55 | id, 56 | show: isShow, 57 | }) 58 | .then(() => { 59 | Steward.app.refresh(); 60 | }); 61 | } 62 | 63 | return { 64 | version, 65 | name: 'Components Manager', 66 | category: 'other', 67 | icon, 68 | title, 69 | commands, 70 | onInput, 71 | onEnter, 72 | canDisabled: false, 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /extension/plugins/steward/custom.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description cusotm the newTab default command 3 | * @author tomasy 4 | * @mail solopea@gmail.com 5 | */ 6 | 7 | import { Command, Plugin } from 'plugins/type'; 8 | import { StewardApp } from 'common/type'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { getURL } from 'helper/extension.helper'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, Toast } = Steward; 14 | 15 | const version = 1; 16 | const name = 'custom'; 17 | const key = 'custom'; 18 | const type = 'keyword'; 19 | const icon = getURL('img/icon.png'); 20 | const title = t(`${name}_title`); 21 | const subtitle = t(`${name}_subtitle`); 22 | const commands: Command[] = [ 23 | { 24 | key, 25 | type, 26 | title, 27 | subtitle, 28 | icon, 29 | editable: true, 30 | }, 31 | ]; 32 | 33 | function onInput() { 34 | return [ 35 | { 36 | key, 37 | title, 38 | desc: subtitle, 39 | icon, 40 | }, 41 | ]; 42 | } 43 | 44 | function onEnter(item, command, query) { 45 | if (query) { 46 | chrome.runtime.sendMessage({ 47 | action: 'saveConfig', 48 | data: { 49 | general: { 50 | cacheLastCmd: false, 51 | defaultPlugin: 'Other', 52 | customCmd: query, 53 | }, 54 | }, 55 | }); 56 | Steward.app.applyCommand(query); 57 | Toast.success(t('save_ok')); 58 | } else { 59 | Toast.warning(t('custom_warning_notempty')); 60 | } 61 | } 62 | 63 | return { 64 | version, 65 | name: 'Custom', 66 | category: 'steward', 67 | type, 68 | icon, 69 | title, 70 | commands, 71 | onInput, 72 | onEnter, 73 | canDisabled: false, 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /extension/plugins/steward/help.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file help command plugin script 3 | * @description help 4 | * @author rong 5 | */ 6 | 7 | import _ from 'underscore'; 8 | 9 | import { StewardApp } from 'common/type'; 10 | import { getURL } from 'helper/extension.helper'; 11 | import { t } from 'helper/i18n.helper'; 12 | import stewardCache from 'main/cache'; 13 | import { Command, Plugin } from 'plugins/type'; 14 | 15 | export default function(Steward: StewardApp): Plugin { 16 | const { chrome, util } = Steward; 17 | 18 | const version = 3; 19 | const name = 'help'; 20 | const key = 'help'; 21 | const type = 'keyword'; 22 | const icon = getURL('iconfont/help.svg'); 23 | const title = t(`${name}_title`); 24 | const subtitle = t(`${name}_subtitle`); 25 | const commands: Command[] = [ 26 | { 27 | key, 28 | type, 29 | title, 30 | subtitle, 31 | icon, 32 | shiftKey: true, 33 | editable: true, 34 | }, 35 | ]; 36 | 37 | // NOTE: Only get the commands when needed, main.js has been immediately obtained 38 | // and then get the object will be empty 39 | function getPlugins(query) { 40 | const allcommands = stewardCache.commands; 41 | const helpList = _.uniq(_.values(allcommands)) 42 | .map(command => { 43 | return { 44 | icon: command.icon, 45 | id: command.key, 46 | name: command.name, 47 | title: `${command.key}: ${command.title}`, 48 | desc: `⇧: ${command.subtitle}`, 49 | type: command.type, 50 | category: command.plugin.category, 51 | }; 52 | }) 53 | .filter(item => item.type === 'keyword') 54 | .filter(function(command) { 55 | return util.matchText(query, `${command.name}${command.title}`); 56 | }); 57 | 58 | return _.sortBy(helpList, 'id'); 59 | } 60 | 61 | function onInput(query) { 62 | return getPlugins(query); 63 | } 64 | 65 | function onEnter(item, command, query, keyStatus) { 66 | const { shiftKey } = keyStatus; 67 | 68 | if (shiftKey) { 69 | util.createTab( 70 | { url: util.getDocumentURL(item.name, item.category) }, 71 | keyStatus, 72 | ); 73 | } else { 74 | return Promise.resolve(`${String(item.id.split(',')[0])} `); 75 | } 76 | } 77 | 78 | return { 79 | version, 80 | name: 'Help', 81 | category: 'steward', 82 | icon, 83 | title, 84 | commands, 85 | onInput, 86 | onEnter, 87 | canDisabled: false, 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /extension/plugins/steward/steward.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description chrome urls 3 | * @author tomasy 4 | * @mail solopea@gmail.com 5 | */ 6 | 7 | import { StewardApp } from 'common/type'; 8 | import { Plugin } from 'plugins/type'; 9 | import { t } from 'helper/i18n.helper'; 10 | import { getURL } from 'helper/extension.helper'; 11 | 12 | export default function(Steward: StewardApp): Plugin { 13 | const { chrome, util, constant } = Steward; 14 | const { stewardPlusTabs, stewardTabs } = constant.BASE 15 | const version = 1; 16 | const name = 'steward'; 17 | const type = 'search'; 18 | const icon = getURL('img/icon.png'); 19 | const title = t(`${name}_title`); 20 | const baseUrl = getURL('options.html'); 21 | 22 | let optionTabs; 23 | 24 | if (EXT_TYPE === 'stewardplus') { 25 | optionTabs = stewardPlusTabs; 26 | } else { 27 | optionTabs = stewardTabs; 28 | } 29 | 30 | optionTabs.push('Backup'); 31 | 32 | function caseFormat(str) { 33 | return str[0].toUpperCase() + str.slice(1); 34 | } 35 | 36 | function onInput(text) { 37 | const filterByName = suggestions => util.getMatches(suggestions, text); 38 | const extType = caseFormat(EXT_TYPE); 39 | const mapTo = itemType => item => { 40 | const isBackup = item === 'Backup'; 41 | 42 | return { 43 | icon, 44 | key: isBackup ? 'app' : itemType, 45 | title: item, 46 | url: item === extType ? baseUrl : `${baseUrl}#/${item.toLowerCase()}`, 47 | weight: 2, 48 | }; 49 | }; 50 | 51 | const tabs = filterByName(optionTabs).map(mapTo('url')); 52 | 53 | return Promise.resolve(tabs); 54 | } 55 | 56 | function onEnter() {} 57 | 58 | return { 59 | version, 60 | name: 'Steward', 61 | category: 'steward', 62 | type, 63 | icon, 64 | title, 65 | onInput, 66 | onEnter, 67 | canDisabled: false, 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /extension/scripts/popup.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | function initTheme(mode) { 3 | chrome.storage.sync.get('themes', function (resp) { 4 | const themes = resp.themes 5 | 6 | if (themes && themes[mode]) { 7 | let cssText = ''; 8 | const theme = themes[mode]; 9 | 10 | for (const prop in theme) { 11 | cssText += `${prop}: ${theme[prop]};`; 12 | } 13 | 14 | document.querySelector('html').style.cssText = cssText; 15 | } 16 | }) 17 | } 18 | 19 | if (window.parent === window) { 20 | initTheme('popup'); 21 | } else { 22 | initTheme('page'); 23 | } 24 | })(); -------------------------------------------------------------------------------- /extension/scss/main.scss: -------------------------------------------------------------------------------- 1 | @import './themes/base.scss'; 2 | 3 | #toast-container em { 4 | color: #d4237a; 5 | font-style: normal; 6 | } 7 | 8 | .cmdbox { 9 | &.exceeded { 10 | font-size: 16px; 11 | } 12 | } -------------------------------------------------------------------------------- /extension/scss/themes/newtab/classical.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --app-background-color: rgba(0, 0, 0, .4); 3 | --newtab-background-color: #000; 4 | --app-width-size: 560px; 5 | --search-input-height: 64px; 6 | --search-input-value-text-color: #fafafa; 7 | --search-input-value-text-size: 26px; 8 | --search-results-height: 432px; 9 | --search-results-scrollbar-width: 2px; 10 | --search-results-scrollbar-color: rgba(0, 0, 0, 0.5); 11 | --selected-suggestion-background-color: rgba(0, 0, 0, 0.2); 12 | --selected-suggestion-title-text-color: #fff; 13 | --selected-suggestion-subtitle-text-color: #ccc; 14 | --highlighted-suggestion-text-color: #fabb2d; 15 | --suggestion-border-color: rgba(209, 209, 209, .1); 16 | --suggestion-height: 48px; 17 | --suggestion-title-text-color: #eee; 18 | --suggestion-title-text-size: 16px; 19 | --suggestion-title-text-weight: 300; 20 | --suggestion-subtitle-text-color: #bbb; 21 | --suggestion-subtitle-text-size: 12px; 22 | --suggestion-subtitle-text-style: "PingFangSC-Light"; 23 | } 24 | 25 | body { 26 | background: var(--app-newtab-background-image); 27 | background-position: center center; 28 | background-size: cover; 29 | background-repeat: no-repeat; 30 | background-attachment: fixed; 31 | } 32 | 33 | #newtab { 34 | display: none; 35 | position: fixed; 36 | width: 100vw; 37 | min-height: 100vh; 38 | left: 0; 39 | top: 0; 40 | z-index: 100000; 41 | } 42 | 43 | .use-iframe { 44 | #newtab { 45 | display: block; 46 | } 47 | #app { 48 | display: none; 49 | } 50 | .container { 51 | display: none; 52 | } 53 | } 54 | 55 | .use-filter { 56 | .main { 57 | position: relative; 58 | 59 | &::before { 60 | position: absolute; 61 | top: 0; 62 | left: 0; 63 | width: 100%; 64 | height: 100%; 65 | z-index: 1; 66 | opacity: .2; 67 | background-color: #fff; 68 | content: ''; 69 | } 70 | 71 | &::after { 72 | position: absolute; 73 | top: 0; 74 | left: 0; 75 | width: 100%; 76 | height: 100%; 77 | background-size: cover; 78 | background-position: center; 79 | background-attachment: fixed; 80 | filter: blur(5px) brightness(110%); 81 | background-image: var(--app-newtab-background-image); 82 | content: ''; 83 | } 84 | 85 | .cmdbox { 86 | position: relative; 87 | z-index: 2; 88 | } 89 | 90 | #list-wrap { 91 | position: relative; 92 | z-index: 2; 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /extension/scss/themes/popup/classical.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --app-background-color: #fff; 3 | --app-width-size: 500px; 4 | --search-input-height: 50px; 5 | --search-input-value-text-color: #000; 6 | --search-input-value-text-size: 22px; 7 | --search-results-height: 400px; 8 | --search-results-scrollbar-width: 2px; 9 | --search-results-scrollbar-color: rgba(0, 0, 0, 0.5); 10 | --selected-suggestion-background-color: rgb(209, 209, 209); 11 | --selected-suggestion-title-text-color: #000; 12 | --selected-suggestion-subtitle-text-color: #000; 13 | --highlighted-suggestion-text-color: red; 14 | --suggestion-height: 44px; 15 | --suggestion-border-color: rgba(209, 209, 209, .1); 16 | --suggestion-title-text-color: #000; 17 | --suggestion-title-text-size: 14px; 18 | --suggestion-title-text-weight: 400; 19 | --suggestion-subtitle-text-color: #000; 20 | --suggestion-subtitle-text-size: 12px; 21 | --suggestion-subtitle-text-style: 'inherit'; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /extension/server/controller/recordsController.ts: -------------------------------------------------------------------------------- 1 | import db, { IRecords } from '../db/index'; 2 | 3 | export function list() { 4 | return db.records.toArray(); 5 | } 6 | 7 | export function save(record: IRecords) { 8 | return db.records.put(record); 9 | } 10 | 11 | export function query(filter: { scope: string, query: string }) { 12 | const { scope, query } = filter; 13 | 14 | return db.records 15 | .where({ 16 | scope, 17 | query, 18 | }) 19 | .toArray(); 20 | } 21 | 22 | export function addTimes(result: IRecords) { 23 | return db.records.update(result.id, { times: result.times + 1 }); 24 | } 25 | 26 | export async function log(attrs: IRecords) { 27 | const { scope, query, result } = attrs; 28 | const resp = await db.records.get({ 29 | scope, 30 | query, 31 | result, 32 | }); 33 | 34 | if (resp) { 35 | return addTimes(resp); 36 | } else { 37 | return save({ 38 | ...attrs, 39 | times: 1, 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /extension/server/db/index.ts: -------------------------------------------------------------------------------- 1 | import Dexie from 'dexie'; 2 | 3 | export class StewardDatabase extends Dexie { 4 | records: Dexie.Table; 5 | 6 | constructor() { 7 | super('steward'); 8 | 9 | this.version(1).stores({ 10 | records: '++id,[scope+query],result,mode,times', 11 | }); 12 | } 13 | } 14 | 15 | export interface IRecords { 16 | id?: number; 17 | scope: string; 18 | query: string; 19 | result: string; 20 | mode: string; 21 | times?: number; 22 | } 23 | 24 | const db = new StewardDatabase(); 25 | 26 | export default db; 27 | -------------------------------------------------------------------------------- /extension/service/bing.ts: -------------------------------------------------------------------------------- 1 | import { WallpaperSource } from 'common/type'; 2 | import * as apiUtils from 'utils/api'; 3 | 4 | export const root = 'https://www.bing.com'; 5 | const baseParams = { 6 | format: 'js', 7 | idx: 0, 8 | n: 1, 9 | nc: Number(new Date()), 10 | mkt: 'zh-CN', 11 | }; 12 | const MAX_IDX = 16; 13 | 14 | function getRandom(to = MAX_IDX) { 15 | return Math.round(Math.random() * to); 16 | } 17 | 18 | export const today = () => { 19 | return apiUtils.fetch(apiUtils.url(root, '/HPImageArchive.aspx'), baseParams); 20 | }; 21 | 22 | export const rand = () => { 23 | return apiUtils.fetch( 24 | apiUtils.url(root, '/HPImageArchive.aspx'), 25 | Object.assign({}, baseParams, { 26 | idx: getRandom(), 27 | }), 28 | ); 29 | }; 30 | 31 | const api = { 32 | today, 33 | rand, 34 | }; 35 | 36 | export default { 37 | name: 'bing', 38 | api: method => () => api[method](), 39 | handle: result => root + result.images[0].url, 40 | weight: 1, 41 | } as WallpaperSource; 42 | -------------------------------------------------------------------------------- /extension/service/desktoppr.ts: -------------------------------------------------------------------------------- 1 | import { WallpaperSource } from 'common/type'; 2 | 3 | import * as apiUtils from '../utils/api'; 4 | 5 | const BASE_URL = 'https://api.desktoppr.co/1/wallpapers'; 6 | 7 | export function getRandom() { 8 | return apiUtils.fetch(`${BASE_URL}/random`); 9 | } 10 | 11 | export default { 12 | name: 'desktoppr', 13 | api: () => getRandom(), 14 | handle: result => result.response.image.url, 15 | weight: 3, 16 | } as WallpaperSource; 17 | -------------------------------------------------------------------------------- /extension/service/index.ts: -------------------------------------------------------------------------------- 1 | export * as bing from './bing' 2 | export * as picsum from './picsum' 3 | export * as nasa from './nasa' 4 | export * as desktoppr from './desktoppr' 5 | export * as pixabay from './pixabay' -------------------------------------------------------------------------------- /extension/service/nasa.ts: -------------------------------------------------------------------------------- 1 | import { WallpaperSource } from 'common/type'; 2 | 3 | import * as apiUtils from '../utils/api'; 4 | 5 | const KEY = 'kxwrn5RQGnJVYU5wwipadjsGjOSrEGbyEihSZcqY'; 6 | const URL = 'https://api.nasa.gov/planetary/apod'; 7 | 8 | export function getList() { 9 | return apiUtils.fetch(URL, { api_key: KEY }); 10 | } 11 | 12 | export default { 13 | name: 'nasa', 14 | api: () => getList(), 15 | handle: result => result.url, 16 | weight: 0.5, 17 | } as WallpaperSource; 18 | -------------------------------------------------------------------------------- /extension/service/picsum.ts: -------------------------------------------------------------------------------- 1 | import { WallpaperSource } from 'common/type'; 2 | 3 | import * as apiUtils from '../utils/api'; 4 | 5 | const STORAGE_KEY = 'picsumids'; 6 | 7 | export const root = 'https://picsum.photos'; 8 | 9 | export function getList() { 10 | return apiUtils.fetch(`${root}/list`); 11 | } 12 | 13 | export function refreshPicsumList() { 14 | getList().then((resp: any) => { 15 | if (resp && resp.length) { 16 | const ids = resp.map(item => item.id); 17 | 18 | try { 19 | window.localStorage.setItem(STORAGE_KEY, JSON.stringify(ids)); 20 | } catch (error) { 21 | console.log(error); 22 | } 23 | } 24 | }); 25 | } 26 | 27 | function getIds() { 28 | try { 29 | return JSON.parse(window.localStorage.getItem(STORAGE_KEY)); 30 | } catch (error) { 31 | console.log(error); 32 | 33 | return [0]; 34 | } 35 | } 36 | 37 | const IMAGE_BASE_URL = `${root}/1920/1080?image=`; 38 | 39 | export function getRandomImage() { 40 | const ids = getIds(); 41 | 42 | if (ids && ids.length) { 43 | const index = Math.round(Math.random() * (ids.length - 1)); 44 | 45 | return Promise.resolve(`${IMAGE_BASE_URL}${ids[index]}`); 46 | } else { 47 | return Promise.resolve(`${IMAGE_BASE_URL}0`); 48 | } 49 | } 50 | 51 | export default { 52 | name: 'picsum', 53 | api: () => getRandomImage(), 54 | handle: result => result, 55 | weight: 2, 56 | } as WallpaperSource; 57 | -------------------------------------------------------------------------------- /extension/service/pixabay.ts: -------------------------------------------------------------------------------- 1 | import { WallpaperSource } from 'common/type'; 2 | 3 | import * as apiUtils from '../utils/api'; 4 | 5 | const APP_KEY = '9599926-06fed5cb1e63825bd24dd87f8'; 6 | const options = { 7 | editors_choice: true, 8 | per_page: 20, 9 | page: 0, 10 | }; 11 | const URL = `https://pixabay.com/api/?key=${APP_KEY}`; 12 | 13 | let page = 0; 14 | 15 | export function getPageList() { 16 | page = page + 1; 17 | options.page = page; 18 | 19 | return apiUtils.fetch(URL, options); 20 | } 21 | 22 | export default function(getRandomOne) { 23 | return { 24 | name: 'pixabay', 25 | api: () => getPageList(), 26 | handle: result => getRandomOne(result.hits).largeImageURL, 27 | weight: 3, 28 | } as WallpaperSource; 29 | } 30 | -------------------------------------------------------------------------------- /extension/service/selection.ts: -------------------------------------------------------------------------------- 1 | import { WallpaperSource } from 'common/type'; 2 | 3 | import * as apiUtils from '../utils/api'; 4 | 5 | const URL = `http://static.oksteward.com/steward-wallpaper.json?t=${Number( 6 | new Date(), 7 | )}`; 8 | 9 | let cached; 10 | 11 | export function getList() { 12 | if (cached) { 13 | return Promise.resolve(cached); 14 | } else { 15 | return apiUtils.fetch(URL).then(result => { 16 | cached = result; 17 | 18 | return cached; 19 | }); 20 | } 21 | } 22 | 23 | export default function(getRandomOne) { 24 | return { 25 | name: 'selection', 26 | api: () => getList(), 27 | handle: result => getRandomOne(result.list), 28 | weight: 1, 29 | } as WallpaperSource; 30 | } 31 | -------------------------------------------------------------------------------- /extension/svg/allowbatch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/app.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/bbs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/bing.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/bookmark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/btc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/chrome.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/del.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/delete-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/diary.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/download-red.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/enter-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/enter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/level0.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/level1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/level2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/level3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/level4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/level5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/exts/wordcard/tag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/google.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/history.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/iframe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/index.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/miniapp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/new-tab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/newversion.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/note.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/notshow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/plusone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/pm25.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/refresh-red.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/save-red.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/selected-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/set.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/blogger.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/buffer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/delicious.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/digg.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/douban.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/facebook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/flipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/friendfeed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/getpocket.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/google_plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/instapaper.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/linkedin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/livejournal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/myspace.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/newsvine.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/pinterest.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/qzone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/renren.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/stumbleupon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/telegram_me.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/tumblr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/viber.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/whatsapp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/xing.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/share-icons/yahoo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/stackoverflow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/star-fill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/tab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/todo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/topsites.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/urlblock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/viewext.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/workflow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/youdao.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/svg/zhihu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension/utils/api.ts: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | 3 | function handleParams(api, data, method) { 4 | return Promise.resolve({ 5 | url: api, 6 | method, 7 | data, 8 | }); 9 | } 10 | 11 | export function url(root = '', path = '/') { 12 | return root + path; 13 | } 14 | 15 | export function fetch(api, data = {}, rawMethod = 'GET') { 16 | return handleParams(api, data, rawMethod).then(options => { 17 | return new Promise((resolve, reject) => { 18 | $.ajax({ 19 | url: options.url, 20 | method: options.method, 21 | data: options.data, 22 | }) 23 | .done(resp => { 24 | if (typeof resp.code === 'undefined') { 25 | resolve(resp); 26 | } else if (resp.code === 200) { 27 | resolve(resp.data); 28 | } else { 29 | reject(resp); 30 | } 31 | }) 32 | .fail(resp => reject(resp)); 33 | }); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /extension/utils/date.ts: -------------------------------------------------------------------------------- 1 | export function format(date = new Date()) { 2 | const ret = [date.getFullYear(), date.getMonth() + 1, date.getDate()].join( 3 | '-', 4 | ); 5 | 6 | return ret; 7 | } 8 | 9 | export function isNewDate(date, last) { 10 | return format(date) !== format(last); 11 | } 12 | -------------------------------------------------------------------------------- /extension/utils/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export * as api from './api' 3 | export * as date from './date' -------------------------------------------------------------------------------- /extension/utils/storage.ts: -------------------------------------------------------------------------------- 1 | const storageFactory = storgaeArea => action => (key, defaultValue) => { 2 | return new Promise(resolve => { 3 | if (action === 'clear') { 4 | storgaeArea[action](resp => resolve(resp)); 5 | } else if (action === 'get') { 6 | storgaeArea[action](key, resp => { 7 | if (resp[key]) { 8 | resolve(resp[key]); 9 | } else if (defaultValue) { 10 | resolve(defaultValue); 11 | } else { 12 | resolve(null); 13 | } 14 | }); 15 | } else { 16 | storgaeArea[action](key, resp => resolve(resp)); 17 | } 18 | }); 19 | }; 20 | 21 | const actions = ['get', 'set', 'remove', 'clear']; 22 | 23 | interface Storage { 24 | sync?: any; 25 | local?: any; 26 | } 27 | const storage: Storage = {}; 28 | 29 | ['sync', 'local'].forEach(storageArea => { 30 | const factory = storageFactory(chrome.storage[storageArea]); 31 | 32 | const methods = (storage[storageArea] = {}); 33 | actions.forEach(action => { 34 | methods[action] = factory(action); 35 | }); 36 | }); 37 | 38 | export default storage; 39 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // This must be specified if "paths" is set 4 | "baseUrl": ".", 5 | // Relative to "baseUrl" 6 | "paths": { 7 | "@/*": [ 8 | "./extension/*" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./extension", 4 | "moduleResolution": "node", 5 | "outDir": "./dist/", 6 | "lib": [ 7 | "es5", "es6", "dom", "dom.iterable" 8 | ], 9 | "noImplicitAny": false, 10 | "allowSyntheticDefaultImports": true, 11 | "module": "es2015", 12 | "target": "es6", 13 | "allowJs": true, 14 | "paths": { 15 | "enum/*": ["enum/*"], 16 | "constant/*": ["constant/*"], 17 | "common/*": ["common/*"], 18 | "utils/*": ["utils/*"], 19 | "service/*": ["service/*"], 20 | "conf/*": ["conf/*"], 21 | "helper/*": ["helper/*"], 22 | "collection/*": ["collection/*"], 23 | "info/*": ["info/*"], 24 | "plugins/*": ["plugins/*"], 25 | "main/*": ["main/*"] 26 | } 27 | } 28 | } --------------------------------------------------------------------------------