├── .gitignore ├── LICENSE ├── README.md ├── README_CN.md ├── build ├── icons │ ├── github_128.png │ ├── github_16.png │ ├── github_38.png │ ├── github_48.png │ └── github_64.png └── manifest.json ├── config ├── path.js ├── webpack.config.js └── webpack.pro.js ├── package.json ├── readme ├── action_button.png ├── create_pull_request.png ├── create_pull_request_after.png ├── create_pull_request_before.png ├── github-extension.png ├── navbar.png ├── repos_size.png └── similar_repos.png └── src ├── css ├── code_review_enhance.css └── recommend_repositories.css ├── entries ├── background.js └── content_script.js └── js ├── code_review_enhance.js ├── create_pull_request.js ├── recommend_repositories.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | /build.zip 2 | /build/src 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 ecmadao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | > A chrome extension for better github experience. 4 | 5 | README:[中文](./README_CN.md) 6 | 7 | ## Feature 8 | 9 | ### Create a pull request 10 | 11 | when you push a new branch to a repository, you will see this in blew: 12 | 13 |  14 | 15 | Then you may click "Compare & pull request" button, and locate to that page: 16 | 17 |  18 | 19 | It's Cool😝. But only cool when you really wanna merge your branch to master. If you have a branch, maybe we can call it "staging", and you use it as a develop & test branch -- so "master" branch is your production branch🤔. 20 | 21 | Your current branch is created from "staging" branch. Besides, it has soooooo many difference with master branch. So then you click "Compare & pull request" button, will it be cool now? NOT AT ALL!!!🙄 To many files to compare, sooooo many times have to spend until this page is loaded. After that, you have to change the base branch to compare again, correctly😞. 22 | 23 | With this chrome extension, after click "Compare & pull request" button, you'll locate to a page which will only compare a base branch with compare branch itself. 24 | 25 |  26 | 27 | ### Better code review experience 28 | 29 | Imagine you are assigned to a pull request. So let's have a code review. 30 | 31 | It is a really really long review, man, and you have no choice but hold on. It seems after hundred of centuries, you scroll to the end of the page! In the end, you have only one task to do -- scroll to the top, click "conversation" button in the navbar, then leave your conversation or merge this request. 32 | 33 |  34 | 35 | With this chrome extension, you'll have a action button on this page at bottom right corner. By using that, you can quickly scroll to top, locate to "conversation" page or "commits" page or "files change" page😝. 36 | 37 |  38 | 39 | they have same func with navbar. 40 | 41 | ### show similar repos 42 | 43 | It's not so accurate at this time, just for fun😆. 44 | 45 | It will search and get six most stared repos by repository name and language. 46 | 47 |  48 | 49 | ### show repos size 50 | 51 |  52 | 53 | ## Download 54 | 55 | [](https://chrome.google.com/webstore/detail/dimfhhiifdbdcjaoijgldompniobhcbd) 56 | 57 | You can download released version in [chrome extension store](https://chrome.google.com/webstore/detail/dimfhhiifdbdcjaoijgldompniobhcbd) 58 | 59 | ## Playground 60 | 61 | - clone & build 62 | 63 | ```bash 64 | $ git clone https://github.com/ecmadao/github-extension.git 65 | $ cd github-extension 66 | $ npm i 67 | $ npm run build 68 | ``` 69 | 70 | - locate your chrome to chrome://extensions/ 71 | - open "developer mode" 72 | - click "load unpacked", then load "build" folder in this repository 73 | 74 | ## ToDo 75 | 76 | - [x] show similar repositories in a repository main page 77 | - [x] show current page in action button when code review 78 | - [x] show repository size 79 | 80 | ## Author 81 | 82 | [ecmadao](https://github.com/ecmadao) 83 | 84 | ## License 85 | 86 | MIT 87 | 88 | -------------------------------------------------------------------------------- 89 | 90 | Enjoy! 91 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | > 一个用于提升`github pull request & code review`的 chrome 插件 4 | 5 | README:[English](./README.md) 6 | 7 | ## 特性 8 | 9 | ### 关于创建`pull request` 10 | 11 | 当你给某个 github 仓库 push 了一个新分支之后,应该会在该仓库的首页看见下面这种页面: 12 | 13 |  14 | 15 | 然后点击"Compare & pull request",就会跳转到创建`pull request`的页面,并且你刚 push 的这个分支会直接和`master`分支比较。 16 | 17 |  18 | 19 | 酷😝。但如果你并不想合并到`master`分支呢?假设我们从`master`创建了一个`staging`分支,它被用于测试环境。而日常的开发和测试都是在基于`staging`所创建的分支,而`master`作为生产环境的分支🤔。 20 | 21 | 既然我们的分支基于`staging`创建,那它或许和`master`有很大的差别。如果这样的话,在我们点击"Compare & pull request"之后,它会直接和`master`分支进行比较的话 -- 那简直太糟糕了 -- 你的页面可能会卡死、耗费很长很长的时间来加载资源🙄,而且只有在加载完资源之后才可以切换`base`分支,然后再比较一次😞。 22 | 23 | 而利用这个插件,我会偷偷改变你要比较的分支。当你点击"Compare & pull request"按钮之后,会跳转到一个仅仅和自身比较的页面,那样的话几乎可以在瞬间完成页面加载。 24 | 25 |  26 | 27 | 我觉得吧,与其初始化的时候加载了错误的`compare`,还不如不提供默认选择,让我自己来选择`pull request`的`base`分支。 28 | 29 | ### 关于`code review`的用户体验 30 | 31 | 假设你被指定参与一个`code review`,而那个`code review`又碰巧很长。直接`merge`了呗?开玩笑,那怎么可能。 32 | 33 | 所以当你认认真真的看完了`pull request file compare`,想要发表点评论,或者合并分支的时候,不得不再将页面滚动到最顶部,点击`navbar`上的按钮。 34 | 35 |  36 | 37 | 这个插件可以为这一步提供一点便利。针对`pull request`页面,它会生成一个位于页面右下角的`action button`浮动按钮,并提供"回到顶部"、"链接到 conversation 页面"、"链接到 commits 页面"、"链接到 files 页面"几个功能😝。 38 | 39 | 那几个按钮和`navbar`的作用一毛一样: 40 | 41 |  42 | 43 | ### 展现类似的开源项目 44 | 45 | 现阶段不是非常准确,该功能供娱乐😆。 46 | 47 | 主要是依据项目名称和语言进行搜索,然后选择展现了 star 数最高的前六个开源项目: 48 | 49 |  50 | 51 | ### 展示仓库大小 52 | 53 |  54 | 55 | -------------------------------------------------------------------------------- 56 | 57 | 其实吧,我上面的那些都仅仅是"治标不治本"而已。因为对一个正确、健康的开发流程而言,本身就不提倡太长的`code review` -- 有那么多改变的代码要看,难以保障 review 质量。而对于插件"改变 pull request 比较的分支"这个功能,本身 github 的`git flow`所提倡的就是:使用`master`分支作为`base`分支,开发分支应该基于`master`分支创建。不过因为自己习惯的原因(公司开发流程的`git flow`和`gitlab work flow`),才会去创建这个 chrome 插件,也希望能帮助到大家吧。 58 | 59 | ## 下载 60 | 61 | [](https://chrome.google.com/webstore/detail/dimfhhiifdbdcjaoijgldompniobhcbd) 62 | 63 | 可在 [chrome商店](https://chrome.google.com/webstore/detail/dimfhhiifdbdcjaoijgldompniobhcbd)下载正式发布版 64 | 65 | ## 本地玩起来 66 | 67 | - clone & build 68 | 69 | ```bash 70 | $ git clone https://github.com/ecmadao/github-extension.git 71 | $ cd github-extension 72 | $ npm i 73 | $ npm run build 74 | ``` 75 | 76 | - 打开 chrome,进入 chrome://extensions/ 77 | - 打开 "开发者模式" 78 | - 点击 "加载未封装的扩展程序",然后加载你刚刚下载的文件夹内的 "build" 文件夹 79 | 80 | ## ToDo 81 | 82 | - [x] 在各仓库的主页面展现和它类似的开源仓库 83 | - [x] code review 页面的 action button 展现当前的页面 84 | - [x] 展示仓库大小 85 | - 更多功能还在思考中。。 86 | 87 | ## author 88 | 89 | [ecmadao](https://github.com/ecmadao) 90 | 91 | ## License 92 | 93 | MIT 94 | -------------------------------------------------------------------------------- /build/icons/github_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/build/icons/github_128.png -------------------------------------------------------------------------------- /build/icons/github_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/build/icons/github_16.png -------------------------------------------------------------------------------- /build/icons/github_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/build/icons/github_38.png -------------------------------------------------------------------------------- /build/icons/github_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/build/icons/github_48.png -------------------------------------------------------------------------------- /build/icons/github_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/build/icons/github_64.png -------------------------------------------------------------------------------- /build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "github code review extension", 4 | "short_name": "review-helper", 5 | "version": "0.5", 6 | "description": "A chrome extension for better github code review.", 7 | "permissions": [ 8 | "tabs", 9 | "https://api.github.com/*", 10 | "https://api.github.com/*/*" 11 | ], 12 | "icons": { 13 | "16": "icons/github_16.png", 14 | "48": "icons/github_48.png", 15 | "64": "icons/github_64.png", 16 | "128": "icons/github_128.png" 17 | }, 18 | "background": { 19 | "scripts": ["src/background.bundle.js"], 20 | "persistent": false 21 | }, 22 | "content_scripts": [ 23 | { 24 | "matches" : ["https://github.com/*", "https://github.com/*/*"], 25 | "js": ["src/content_script.bundle.js"], 26 | "css": ["src/content_script.bundle.css"] 27 | } 28 | ], 29 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" 30 | } 31 | -------------------------------------------------------------------------------- /config/path.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const CURRENT_PATH = path.resolve(__dirname); // 获取到当前目录 4 | const ROOT_PATH = path.join(__dirname, '../'); // 项目根目录 5 | const MODULES_PATH = path.join(ROOT_PATH, './node_modules'); // node包目录 6 | const BUILD_PATH = path.join(ROOT_PATH, './build/src'); // 最后输出放置公共资源的目录 7 | const ENTRY_PATH = path.join(ROOT_PATH, './src/entries'); // webpack入口文件 8 | 9 | module.exports = { 10 | ROOT_PATH, 11 | BUILD_PATH, 12 | CURRENT_PATH, 13 | ENTRY_PATH 14 | }; 15 | -------------------------------------------------------------------------------- /config/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const ExtractTextPlugin = require("extract-text-webpack-plugin"); 3 | const CleanPlugin = require('clean-webpack-plugin'); 4 | const PATH = require('./path'); 5 | const path = require('path'); 6 | const fs = require('fs'); 7 | const entryFiles = fs.readdirSync(PATH.ENTRY_PATH); 8 | 9 | const files = []; 10 | const entries = {}; 11 | 12 | entryFiles 13 | .filter(file => 14 | file.split('.')[0] && file.split('.').slice(-1)[0] === 'js' 15 | ) 16 | .forEach(file => { 17 | const filename = file.split('.')[0]; 18 | const filepath = path.join(PATH.ENTRY_PATH, file) 19 | entries[filename] = filepath; 20 | }); 21 | 22 | module.exports = { 23 | entry: entries, 24 | output: { 25 | filename: '[name].bundle.js', 26 | path: PATH.BUILD_PATH 27 | }, 28 | module: { 29 | loaders: [ 30 | {test: require.resolve("jquery"), loader: "expose?jQuery"}, 31 | {test: require.resolve("jquery"), loader: "expose?$"}, 32 | {test: /\.css$/, loader: ExtractTextPlugin.extract("style", "css")}, 33 | { 34 | test: /\.js$/, 35 | exclude: /(node_modules)/, 36 | loader: ["babel-loader"], 37 | query: { 38 | presets: ["es2015"] 39 | } 40 | } 41 | ], 42 | }, 43 | resolve: { 44 | extensions: ['', '.js', '.jsx'], 45 | }, 46 | plugins: [ 47 | new ExtractTextPlugin("[name].bundle.css", { 48 | allChunks: true 49 | }), 50 | new webpack.ProvidePlugin({ 51 | $: "jquery", 52 | jQuery: "jquery", 53 | "window.jQuery": "jquery" 54 | }), 55 | new CleanPlugin(PATH.BUILD_PATH, { 56 | root: PATH.ROOT_PATH, 57 | verbose: true 58 | }) 59 | ], 60 | debug: true, 61 | displayErrorDetails: true, 62 | outputPathinfo: true, 63 | devtool: "cheap-module-eval-source-map" 64 | }; 65 | -------------------------------------------------------------------------------- /config/webpack.pro.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | var config = module.exports = require('./webpack.config'); 3 | 4 | config.plugins.push( 5 | new webpack.optimize.UglifyJsPlugin({ 6 | compress: { 7 | warnings: false 8 | } 9 | }), 10 | new webpack.optimize.DedupePlugin(), 11 | new webpack.optimize.OccurenceOrderPlugin(), 12 | new webpack.DefinePlugin({ 13 | 'process.env.NODE_ENV': '"production"' 14 | }), 15 | new webpack.NoErrorsPlugin() 16 | ); 17 | config.debug = false; 18 | config.devtool = "cheap-source-map"; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-extension", 3 | "version": "0.0.1", 4 | "description": "A chrome extension for better github code review.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "export NODE_ENV=production && npm run build_pro", 9 | "build_pro": "./node_modules/webpack/bin/webpack.js --config config/webpack.pro.js -p", 10 | "build_dev": "./node_modules/webpack/bin/webpack.js --config config/webpack.config.js" 11 | }, 12 | "keywords": [ 13 | "github", 14 | "chrome-extension" 15 | ], 16 | "author": "ecmadao", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/ecmadao/github-extension.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/ecmadao/github-extension/issues" 23 | }, 24 | "homepage": "https://github.com/ecmadao/github-extension#readme", 25 | "license": "MIT", 26 | "devDependencies": { 27 | "babel-loader": "^6.2.5", 28 | "babel-preset-es2015": "^6.16.0", 29 | "babel-core": "^6.14.0", 30 | "style-loader": "^0.13.1", 31 | "clean-webpack-plugin": "^0.1.10", 32 | "css-loader": "^0.23.1", 33 | "es6-promise": "^3.2.1", 34 | "exports-loader": "^0.6.3", 35 | "expose-loader": "^0.7.1", 36 | "extract-text-webpack-plugin": "^1.0.1", 37 | "webpack": "^1.13.2" 38 | }, 39 | "dependencies": { 40 | "jquery": "^3.1.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /readme/action_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/action_button.png -------------------------------------------------------------------------------- /readme/create_pull_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/create_pull_request.png -------------------------------------------------------------------------------- /readme/create_pull_request_after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/create_pull_request_after.png -------------------------------------------------------------------------------- /readme/create_pull_request_before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/create_pull_request_before.png -------------------------------------------------------------------------------- /readme/github-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/github-extension.png -------------------------------------------------------------------------------- /readme/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/navbar.png -------------------------------------------------------------------------------- /readme/repos_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/repos_size.png -------------------------------------------------------------------------------- /readme/similar_repos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecmadao/github-extension/5b71091d2d798de3f5b74ab37a304a98ea62ee4b/readme/similar_repos.png -------------------------------------------------------------------------------- /src/css/code_review_enhance.css: -------------------------------------------------------------------------------- 1 | /* action button main wrapper */ 2 | .git_action_button_wrapper { 3 | position: fixed; 4 | z-index: 999; 5 | bottom: -50px; 6 | right: 40px; 7 | transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 8 | -webkit-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 9 | } 10 | 11 | .git_action_button_wrapper.active { 12 | bottom: 40px; 13 | } 14 | 15 | .git_action_button_wrapper:hover .code_review_tab_wrapper { 16 | opacity: 1; 17 | visibility: visible; 18 | left: -155px; 19 | z-index: 1; 20 | } 21 | 22 | /* action button */ 23 | .git_action_button { 24 | background-color: #fff; 25 | position: relative; 26 | border-radius: 50%; 27 | cursor: pointer; 28 | box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.12), 0 0 4px 0 rgba(0, 0, 0, 0.08) !important; 29 | -webkit-box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.12), 0 0 4px 0 rgba(0, 0, 0, 0.08) !important; 30 | transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 31 | -webkit-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 32 | } 33 | 34 | .git_action_button:hover { 35 | box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08) !important; 36 | -webkit-box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08) !important; 37 | } 38 | 39 | .github_scroll_top { 40 | width: 50px; 41 | height: 50px; 42 | z-index: 9; 43 | } 44 | 45 | .code_review_tab { 46 | width: 40px; 47 | height: 40px; 48 | display: block; 49 | margin: 5px; 50 | float: left; 51 | color: #424242; 52 | } 53 | 54 | .code_review_tab.active, 55 | .code_review_tab:hover { 56 | background-color: #616161; 57 | color: #fff; 58 | } 59 | 60 | /* scroll to top icon */ 61 | .scroll_top_icon { 62 | position: absolute; 63 | top: 40%; 64 | left: 50%; 65 | transform: translate(-50%, -50%); 66 | -webkit-transform: translate(-50%, -50%); 67 | } 68 | 69 | .scroll_top_icon::after, 70 | .scroll_top_icon::before { 71 | content: ''; 72 | display: block; 73 | width: 2px; 74 | height: 13px; 75 | background-color: #616161; 76 | transform-origin: top; 77 | -webkit-transform-origin: top; 78 | position: absolute; 79 | top: 0; 80 | left: 0; 81 | } 82 | 83 | .scroll_top_icon::before { 84 | transform: rotate(42deg); 85 | -webkit-transform: rotate(42deg); 86 | } 87 | 88 | .scroll_top_icon::after { 89 | transform: rotate(318deg); 90 | -webkit-transform: rotate(318deg); 91 | } 92 | 93 | /* code review icon*/ 94 | .code_review_icon { 95 | position: absolute; 96 | top: 50%; 97 | left: 50%; 98 | transform: translate(-50%, -50%); 99 | } 100 | 101 | /* topbar icons */ 102 | .code_review_tab_wrapper { 103 | position: absolute; 104 | z-index: -1; 105 | opacity: 0; 106 | visibility: hidden; 107 | height: 50px; 108 | width: 180px; 109 | top: 0; 110 | left: 0; 111 | transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 112 | -webkit-transition: all 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 113 | } 114 | 115 | .code_review_tab_wrapper.active { 116 | opacity: 1; 117 | visibility: visible; 118 | z-index: 1; 119 | } 120 | -------------------------------------------------------------------------------- /src/css/recommend_repositories.css: -------------------------------------------------------------------------------- 1 | .repo_wrapper { 2 | width: 100%; 3 | margin: 15px 0 25px 0; 4 | border: 1px solid #ddd; 5 | border-radius: 3px; 6 | } 7 | 8 | .repo_wrapper .repo_wrapper_title { 9 | padding: 0 1.7%; 10 | font-size: 16px; 11 | height: 35px; 12 | line-height: 35px; 13 | border-bottom: 1px solid #ddd; 14 | } 15 | 16 | .repo_wrapper .repo_wrapper_language { 17 | float: right; 18 | color: rgb(158, 158, 158); 19 | } 20 | 21 | .repo_wrapper .repo_container { 22 | display: inline-block; 23 | width: 33.3%; 24 | border-right: 1px solid #f0f0f0; 25 | border-radius: 2px; 26 | transition: all 400ms; 27 | -webkit-transition: all 400ms; 28 | background-color: #fff; 29 | } 30 | 31 | .repo_wrapper .repo_container:nth-child(2), 32 | .repo_wrapper .repo_container:nth-child(3), 33 | .repo_wrapper .repo_container:nth-child(4) { 34 | border-bottom: 1px solid #f0f0f0; 35 | } 36 | 37 | .repo_wrapper .repo_container:nth-child(3n + 1) { 38 | border-right: none; 39 | } 40 | 41 | .repo_wrapper .repo_container:hover { 42 | box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08); 43 | -webkit-box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.12), 0 0 8px 0 rgba(0, 0, 0, 0.08); 44 | } 45 | 46 | .repo_container .repo_desc, 47 | .repo_container .repo_title, 48 | .repo_container .repo_info { 49 | padding: 10px 15px; 50 | overflow: hidden; 51 | text-overflow: ellipsis; 52 | white-space: nowrap; 53 | width: 100%; 54 | } 55 | .repo_container .repo_desc, 56 | .repo_container .repo_info { 57 | padding: 5px 15px; 58 | font-size: 12px; 59 | color: #9E9E9E; 60 | } 61 | .repo_container .repo_title, 62 | .repo_container .repo_info a { 63 | transition: all 200ms; 64 | -webkit-transition: all 200ms; 65 | } 66 | 67 | .repo_container .repo_title { 68 | display: block; 69 | color: #666; 70 | } 71 | 72 | .repo_container .repo_info .repo_stars { 73 | float: right; 74 | } 75 | .repo_container .repo_info a { 76 | color: #9E9E9E; 77 | text-decoration: none; 78 | } 79 | .repo_container .repo_info a:hover { 80 | color: #1976D2; 81 | } 82 | 83 | /* github_repo_size */ 84 | .github_repo_size { 85 | overflow: hidden; 86 | text-overflow: ellipsis; 87 | white-space: nowrap; 88 | } 89 | 90 | .github_repo_size svg { 91 | width: 16px; 92 | height: 16px; 93 | fill: #999; 94 | color: #999; 95 | vertical-align: text-bottom; 96 | display: inline-block; 97 | } 98 | -------------------------------------------------------------------------------- /src/entries/background.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | chrome.tabs.query({currentWindow: true, active : false}, (tabs) => { 3 | tabs.forEach((tab) => { 4 | chrome.tabs.reload(tab.id); 5 | }); 6 | }); 7 | })(); 8 | -------------------------------------------------------------------------------- /src/entries/content_script.js: -------------------------------------------------------------------------------- 1 | import '../css/code_review_enhance.css'; 2 | import '../css/recommend_repositories.css'; 3 | import ActionButton from '../js/code_review_enhance'; 4 | import initialPullRequest from '../js/create_pull_request'; 5 | import RecommendRepo from '../js/recommend_repositories'; 6 | 7 | initialPullRequest(); 8 | 9 | const actionButton = new ActionButton(); 10 | actionButton.initial().listenUrlChange(); 11 | 12 | const recommendRepo = new RecommendRepo(); 13 | recommendRepo.initial().listenUrlChange(); 14 | -------------------------------------------------------------------------------- /src/js/code_review_enhance.js: -------------------------------------------------------------------------------- 1 | import { 2 | matchUrl, 3 | activePage, 4 | originalURL 5 | } from './utils'; 6 | 7 | class ActionButton { 8 | constructor() { 9 | this.url = originalURL(); 10 | this.canInitialReviewButton = matchUrl(this.url); 11 | this.actionButton = null; 12 | this.reviewButton = null; 13 | } 14 | 15 | initial() { 16 | this._addScrollButton(); 17 | this._listenWindowScroll(); 18 | return this; 19 | } 20 | 21 | listenUrlChange() { 22 | const observer = new window.WebKitMutationObserver((mutations) => { 23 | const currentUrl = originalURL(); 24 | if (currentUrl === this.url) { 25 | return; 26 | } 27 | this.url = currentUrl; 28 | const matchReviewUrl = matchUrl(currentUrl); 29 | if (!matchReviewUrl && this.canInitialReviewButton) { 30 | this._removeReviewButton(); 31 | return; 32 | } 33 | if (matchReviewUrl && !this.reviewButton && !this.canInitialReviewButton) { 34 | this.canInitialReviewButton = matchReviewUrl; 35 | this._initialReviewButton(); 36 | return; 37 | } 38 | if (matchReviewUrl) { 39 | this._handleUrlChange(); 40 | } 41 | }); 42 | try { 43 | observer.observe($('#js-repo-pjax-container')[0], { 44 | subtree: true, 45 | characterData: true, 46 | childList: true 47 | }); 48 | } catch (e) {} 49 | } 50 | 51 | _removeReviewButton() { 52 | this.canInitialReviewButton = false; 53 | this.reviewButton && this.reviewButton.remove(); 54 | this.reviewButton = null; 55 | } 56 | 57 | _addScrollButton() { 58 | this.actionButton = $(this._actionButtonTemplate()); 59 | $('body').append(this.actionButton); 60 | this._bindButtonAction(); 61 | if (this.canInitialReviewButton) { 62 | this._initialReviewButton(); 63 | } 64 | } 65 | 66 | _bindButtonAction() { 67 | const $scrollButton = $('.github_scroll_top'); 68 | $scrollButton.on('click', () => { 69 | $('html, body').animate({ 70 | scrollTop: 0 71 | }, 'slow'); 72 | }); 73 | } 74 | 75 | _handleUrlChange() { 76 | this.reviewButton.find('.code_review_tab').each((i, button) => { 77 | const href = $(button).attr('href'); 78 | if (activePage(href)) { 79 | $(button).addClass('active').siblings().removeClass('active'); 80 | } 81 | }); 82 | } 83 | 84 | _listenWindowScroll() { 85 | const $document = $(document); 86 | const $actionButton = $('.git_action_button_wrapper'); 87 | $(window).scroll(() => { 88 | const $currentTop = $document.scrollTop(); 89 | if ($currentTop > 300) { 90 | $actionButton.addClass('active'); 91 | } else { 92 | $actionButton.removeClass('active'); 93 | } 94 | }); 95 | } 96 | 97 | _initialReviewButton() { 98 | this.reviewButton = $(this.topBarButtonTemplate); 99 | this.actionButton.append(this.reviewButton); 100 | } 101 | 102 | _actionButtonTemplate() { 103 | return `
`; 106 | } 107 | 108 | get scrollButtonTemplate() { 109 | return ` `; 112 | } 113 | 114 | get topBarButtonTemplate() { 115 | return `