├── public ├── favicon.ico ├── app │ └── background.js ├── css │ └── root.css ├── manifest.json └── index.html ├── .github └── ISSUE_TEMPLATE │ ├── ask-question.md │ ├── feature_request.md │ └── bug_report.md ├── src ├── index.js ├── App.test.js ├── App.css ├── App.js ├── content.js ├── logo.svg └── registerServiceWorker.js ├── config ├── jest │ ├── fileTransform.js │ └── cssTransform.js ├── polyfills.js ├── paths.js ├── env.js ├── webpackDevServer.config.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── .gitignore ├── scripts ├── test.js ├── start.js └── build.js ├── LICENSE ├── README.md ├── CODE_OF_CONDUCT.md └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satendra02/react-chrome-extension/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ask-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ask question 3 | about: What is in your mind 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import registerServiceWorker from './registerServiceWorker'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | registerServiceWorker(); 8 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/en/webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | .history/ -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /public/app/background.js: -------------------------------------------------------------------------------- 1 | // Called when the user clicks on the browser action 2 | chrome.action.onClicked.addListener(function (tab) { 3 | // Send a message to the active tab 4 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { 5 | var activeTab = tabs[0]; 6 | chrome.tabs.sendMessage(activeTab.id, { 7 | message: "clicked_browser_action", 8 | }); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /public/css/root.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | 7 | #my-extension-root{ 8 | width: 400px; 9 | height: 100%; 10 | position: fixed; 11 | top: 0px; 12 | right: 0px; 13 | z-index: 2147483647; 14 | background-color: white; 15 | box-shadow: 0px 0px 5px #0000009e; 16 | } 17 | 18 | #my-extension-root iframe { 19 | width: 100%; 20 | height: 100%; 21 | border: none; 22 | } -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-title { 18 | font-size: 1.5em; 19 | } 20 | 21 | .App-intro { 22 | font-size: large; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { transform: rotate(0deg); } 27 | to { transform: rotate(360deg); } 28 | } 29 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "My Extension", 3 | "name": "My Extension", 4 | "version": "1.1", 5 | "manifest_version": 3, 6 | "background": { 7 | "service_worker": "app/background.js" 8 | }, 9 | "action": {}, 10 | "content_scripts": [ 11 | { 12 | "matches": [""], 13 | "css": ["/css/root.css"], 14 | "js": ["/static/js/content.js"] 15 | } 16 | ], 17 | "web_accessible_resources": [ 18 | { 19 | "resources": ["/static/css/content.css", "/static/media/*"], 20 | "matches": [""] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof Promise === 'undefined') { 4 | // Rejection tracking prevents a common issue where React gets into an 5 | // inconsistent state due to an error, but it gets swallowed by a Promise, 6 | // and the user has no idea what causes React's erratic future behavior. 7 | require('promise/lib/rejection-tracking').enable(); 8 | window.Promise = require('promise/lib/es6-extensions.js'); 9 | } 10 | 11 | // fetch() polyfill for making API calls. 12 | require('whatwg-fetch'); 13 | 14 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet. 15 | // We don't polyfill it in the browser--this is user's responsibility. 16 | if (process.env.NODE_ENV === 'test') { 17 | require('raf').polyfill(global); 18 | } 19 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | /*global chrome*/ 2 | 3 | import React, { Component } from 'react'; 4 | import logo from './logo.svg'; 5 | import './App.css'; 6 | 7 | class App extends Component { 8 | render() { 9 | return ( 10 |
11 |
12 | {this.props.isExt ? 13 | logo 14 | : 15 | logo 16 | } 17 | 18 |

Welcome to React

19 |
20 |

21 | To get started, edit src/App.js and save to reload. 22 |

23 |
24 | ); 25 | } 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | const jest = require('jest'); 19 | let argv = process.argv.slice(2); 20 | 21 | // Watch unless on CI or in coverage mode 22 | if (!process.env.CI && argv.indexOf('--coverage') < 0) { 23 | argv.push('--watch'); 24 | } 25 | 26 | 27 | jest.run(argv); 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Satendra Rai 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 | -------------------------------------------------------------------------------- /src/content.js: -------------------------------------------------------------------------------- 1 | /*global chrome*/ 2 | /* src/content.js */ 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import Frame, { FrameContextConsumer }from 'react-frame-component'; 6 | import App from "./App"; 7 | class Main extends React.Component { 8 | render() { 9 | return ( 10 | ]}> 11 | 12 | { 13 | ({document, window}) => { 14 | return 15 | } 16 | } 17 | 18 | 19 | ) 20 | } 21 | } 22 | 23 | const app = document.createElement('div'); 24 | app.id = "my-extension-root"; 25 | 26 | document.body.appendChild(app); 27 | ReactDOM.render(
, app); 28 | 29 | app.style.display = "none"; 30 | 31 | chrome.runtime.onMessage.addListener( 32 | function(request, sender, sendResponse) { 33 | if( request.message === "clicked_browser_action") { 34 | toggle(); 35 | } 36 | } 37 | ); 38 | 39 | function toggle(){ 40 | if(app.style.display === "none"){ 41 | app.style.display = "block"; 42 | }else{ 43 | app.style.display = "none"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | 7 | // Make sure any symlinks in the project folder are resolved: 8 | // https://github.com/facebookincubator/create-react-app/issues/637 9 | const appDirectory = fs.realpathSync(process.cwd()); 10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath); 11 | 12 | const envPublicUrl = process.env.PUBLIC_URL; 13 | 14 | function ensureSlash(path, needsSlash) { 15 | const hasSlash = path.endsWith('/'); 16 | if (hasSlash && !needsSlash) { 17 | return path.substr(path, path.length - 1); 18 | } else if (!hasSlash && needsSlash) { 19 | return `${path}/`; 20 | } else { 21 | return path; 22 | } 23 | } 24 | 25 | const getPublicUrl = appPackageJson => 26 | envPublicUrl || require(appPackageJson).homepage; 27 | 28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer 29 | // "public path" at which the app is served. 30 | // Webpack needs to know it to put the right