Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
thepeshka committed Apr 14, 2019
0 parents commit bc84b0b
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
### 🙋‍♂️ Made by [@thekitze](https://twitter.com/thekitze)

### Other projects:
- 🏫 [React Academy](https://reactacademy.io) - Interactive React and GraphQL workshops
- 💌 [Twizzy](https://twizzy.app) - A standalone app for Twitter DM
- 💻 [Sizzy](https://sizzy.co) - A tool for testing responsive design on multiple devices at once
- 🤖 [JSUI](https://github.com/kitze/JSUI) - A powerful UI toolkit for managing JavaScript apps

---

# React + Electron = 😍

An example of using create-react-app and Electron.

## Scripts
```yarn start``` will start the Electron app and the React app at the same time.
```yarn build``` will build the React app and package it along the Electron app.

## Read more
You can read more about it in [my Medium article](https://medium.com/@kitze/%EF%B8%8F-from-react-to-an-electron-app-ready-for-production-a0468ecb1da3).
36 changes: 36 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "netstat",
"description": "Simple netstat popup docked in tray",
"author": "peshka",
"version": "0.0.1",
"private": true,
"dependencies": {
"cross-env": "5.1.6",
"electron-is-dev": "0.3.0",
"electron-log": "^2.2.6",
"react": "16.4.0",
"react-dom": "16.4.0",
"axios": "^0.18.0",
"copy-to-clipboard": "^3.1.0"
},
"devDependencies": {
"concurrently": "3.5.1",
"electron": "2.0.2",
"electron-builder": "^20.15.1",
"prettier": "^1.4.4",
"react-scripts": "1.1.4",
"wait-on": "2.1.0"
},
"main": "public/electron.js",
"homepage": "./",
"scripts": {
"react-start": "react-scripts start",
"react-build": "react-scripts build",
"react-test": "react-scripts test --env=jsdom",
"react-eject": "react-scripts eject",
"electron-build": "electron-builder",
"release": "yarn react-build && electron-builder --publish=always",
"build": "yarn react-build && yarn electron-build",
"start": "concurrently \"cross-env BROWSER=none yarn react-start\" \"wait-on http://localhost:3000 && electron .\""
}
}
54 changes: 54 additions & 0 deletions public/electron.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const electron = require("electron");
const app = electron.app;
const Tray = electron.Tray;
const BrowserWindow = electron.BrowserWindow;

const path = require("path");
const isDev = require("electron-is-dev");

let mainWindow;
let tray = null;

function createWindow() {
mainWindow = new BrowserWindow({
width: 260,
height: 78,
alwaysOnTop: true,
show: false,
frame: false,
skipTaskbar: true
});
mainWindow.loadURL(
isDev
? "http://localhost:3000"
: `file://${path.join(__dirname, "../build/index.html")}`
);
mainWindow.on("closed", () => {
mainWindow = null;
tray.destroy();
});
mainWindow.on("blur", () => {mainWindow.hide()});
tray = new Tray(
isDev
? "public/favicon.ico"
: path.join(__dirname, "../build/favicon.ico"));
tray.on("click", (_, __, position) => {
mainWindow.setPosition(position.x - 260, position.y > 200?position.y - 98:position.y + 20);
mainWindow.show();
});
tray.on("right-click", () => {mainWindow.close()})
}

app.on("ready", createWindow);

app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});

app.on("activate", () => {
if (mainWindow === null) {
createWindow();
}
});
Binary file added public/favicon.ico
Binary file not shown.
15 changes: 15 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Roboto:500" rel="stylesheet">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
15 changes: 15 additions & 0 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
7 changes: 7 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.row {
display: flex;
justify-content: space-between;
padding: 10px;
user-select: none;
cursor: default;
}
33 changes: 33 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { Component } from 'react';
import {LocalIP, PublicIP} from "./utils";
import './App.css';
import copy from 'copy-to-clipboard';

class App extends Component {
state = {
localIp: "",
publicIp: ""
};

componentDidMount(){
LocalIP((localIp) => this.setState({localIp}));
PublicIP((publicIp) => this.setState({publicIp}));
}

render() {
return (
<div className="App">
<div className="row">
<div className="cell">Your local IP</div>
<div className="cell" onClick={() => copy(this.state.localIp)}>{this.state.localIp}</div>
</div>
<div className="row">
<div className="cell">Your public IP</div>
<div className="cell" onClick={() => copy(this.state.publicIp)}>{this.state.publicIp}</div>
</div>
</div>
);
}
}

export default App;
12 changes: 12 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
body {
margin: 0;
padding: 0;
border: 0;
font-family: 'Roboto', sans-serif;
background: #47488b;
color: #eee5df;
}

* {
overflow: hidden;
}
6 changes: 6 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';

ReactDOM.render(<App />, document.getElementById('root'));
42 changes: 42 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import axios from 'axios';

export const LocalIP = (onNewIP) => {
var myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var pc = new myPeerConnection({
iceServers: []
}),
noop = function() {
},
localIPs = {},
ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g,
key;

function iterateIP(ip) {
if (!localIPs[ip]) onNewIP(ip);
localIPs[ip] = true;
}

//create a bogus data channel
pc.createDataChannel("");

// create offer and set local description
pc.createOffer(function(sdp) {
sdp.sdp.split("\n").forEach(function(line) {
if (line.indexOf("candidate") < 0) return;
line.match(ipRegex).forEach(iterateIP);
});

pc.setLocalDescription(sdp, noop, noop);
}, noop);

//listen for candidate events
pc.onicecandidate = function(ice) {
if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
ice.candidate.candidate.match(ipRegex).forEach(iterateIP);
};
};

export const PublicIP = (onNewIP) => {
axios.get('https://ipv4.icanhazip.com/')
.then(({data}) => onNewIP(data?data.trim():null));
};

0 comments on commit bc84b0b

Please sign in to comment.