Skip to content

Commit a566e94

Browse files
author
Ben Richards
committed
initial commit
0 parents  commit a566e94

25 files changed

+9482
-0
lines changed

.env

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
PACKAGE=true
2+
DEV=http://localhost:3000

.gitignore

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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*

README.md

+1,901
Large diffs are not rendered by default.

main.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const electron = require('electron')
2+
// Module to control application life.
3+
const app = electron.app
4+
// Module to create native browser window.
5+
const BrowserWindow = electron.BrowserWindow
6+
7+
const path = require('path')
8+
const url = require('url')
9+
10+
require('dotenv').config()
11+
12+
// Keep a global reference of the window object, if you don't, the window will
13+
// be closed automatically when the JavaScript object is garbage collected.
14+
let mainWindow
15+
16+
function createWindow () {
17+
// Create the browser window.
18+
mainWindow = new BrowserWindow({width: 1500, height: 900})
19+
20+
if (process.env.PACKAGE === 'true') {
21+
// and load the index.html of the app.
22+
mainWindow.loadURL(url.format({
23+
pathname: path.join(__dirname, 'build/index.html'),
24+
protocol: 'file:',
25+
slashes: true
26+
}))
27+
} else {
28+
require('electron-reload')(__dirname, {
29+
electron: path.join(__dirname, 'node_modules/.bin/electron')
30+
})
31+
mainWindow.loadURL(process.env.DEV)
32+
mainWindow.webContents.openDevTools()
33+
}
34+
35+
// Emitted when the window is closed.
36+
mainWindow.on('closed', function () {
37+
// Dereference the window object, usually you would store windows
38+
// in an array if your app supports multi windows, this is the time
39+
// when you should delete the corresponding element.
40+
mainWindow = null
41+
})
42+
}
43+
44+
// This method will be called when Electron has finished
45+
// initialization and is ready to create browser windows.
46+
// Some APIs can only be used after this event occurs.
47+
app.on('ready', createWindow)
48+
49+
// Quit when all windows are closed.
50+
app.on('window-all-closed', function () {
51+
// On OS X it is common for applications and their menu bar
52+
// to stay active until the user quits explicitly with Cmd + Q
53+
if (process.platform !== 'darwin') {
54+
app.quit()
55+
}
56+
})
57+
58+
app.on('activate', function () {
59+
// On OS X it's common to re-create a window in the app when the
60+
// dock icon is clicked and there are no other windows open.
61+
if (mainWindow === null) {
62+
createWindow()
63+
}
64+
})
65+
66+
// In this file you can include the rest of your app's specific main process
67+
// code. You can also put them in separate files and require them here.

package.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "MsgpackEdit",
3+
"version": "0.1.0",
4+
"main": "main.js",
5+
"private": true,
6+
"devDependencies": {
7+
"dotenv": "^4.0.0",
8+
"electron": "^1.6.11",
9+
"electron-reload": "^1.2.1",
10+
"react-scripts": "1.0.7"
11+
},
12+
"dependencies": {
13+
"msgpack-lite": "^0.1.26",
14+
"prop-types": "^15.5.10",
15+
"react": "^15.5.4",
16+
"react-dom": "^15.5.4",
17+
"react-dropzone": "^3.13.2",
18+
"react-fontawesome": "^1.6.1",
19+
"react-input-autosize": "^1.1.4"
20+
},
21+
"homepage": "./",
22+
"scripts": {
23+
"start": "react-scripts start",
24+
"build": "react-scripts build",
25+
"test": "react-scripts test --env=jsdom",
26+
"eject": "react-scripts eject",
27+
"electron": "./node_modules/.bin/electron ."
28+
}
29+
}

public/favicon.ico

24.3 KB
Binary file not shown.

public/index.html

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6+
<meta name="theme-color" content="#000000">
7+
<!--
8+
manifest.json provides metadata used when your web app is added to the
9+
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
10+
-->
11+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
12+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
13+
<link href='https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' rel='stylesheet' integrity='sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN' crossorigin='anonymous'>
14+
<!--
15+
Notice the use of %PUBLIC_URL% in the tags above.
16+
It will be replaced with the URL of the `public` folder during the build.
17+
Only files inside the `public` folder can be referenced from the HTML.
18+
19+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
20+
work correctly both with client-side routing and a non-root public URL.
21+
Learn how to configure a non-root public URL by running `npm run build`.
22+
-->
23+
<title>React App</title>
24+
</head>
25+
<body>
26+
<noscript>
27+
You need to enable JavaScript to run this app.
28+
</noscript>
29+
<div id="root"></div>
30+
<!--
31+
This HTML file is a template.
32+
If you open it directly in the browser, you will see an empty page.
33+
34+
You can add webfonts, meta tags, or analytics to this file.
35+
The build step will place the bundled scripts into the <body> tag.
36+
37+
To begin the development, run `npm start` or `yarn start`.
38+
To create a production bundle, use `npm run build` or `yarn build`.
39+
-->
40+
</body>
41+
</html>

public/manifest.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"short_name": "React App",
3+
"name": "Create React App Sample",
4+
"icons": [
5+
{
6+
"src": "favicon.ico",
7+
"sizes": "192x192",
8+
"type": "image/png"
9+
}
10+
],
11+
"start_url": "./index.html",
12+
"display": "standalone",
13+
"theme_color": "#000000",
14+
"background_color": "#ffffff"
15+
}

src/App.css

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
.App {
2+
height: 90vh;
3+
width: 90vw;
4+
max-width: 1000px;
5+
max-height: 800px;
6+
min-height: 800px;
7+
margin: auto;
8+
background-color: whitesmoke;
9+
padding: 50px;
10+
border-radius: 5px;
11+
box-shadow: 0px 2px 8px #888888;
12+
}
13+
14+
.downloadButton {
15+
display: flex;
16+
justify-content: center;
17+
align-items: center;
18+
font-size: 16px;
19+
color: black;
20+
height: 70px;
21+
width: 30%;
22+
min-width: 100px;
23+
background-color: lightblue;
24+
border-radius: 10px;
25+
box-shadow: 0px 2px 8px #888888;
26+
font-family: sans-serif;
27+
margin-left: 50%;
28+
}
29+
30+
.dropzone {
31+
font-size: 13px;
32+
width: 40%;
33+
margin-right: -10%;
34+
max-width: 500px;
35+
height: 200px;
36+
display: flex;
37+
justify-content: center;
38+
align-items: center;
39+
border-radius: 10px;
40+
padding: 10px;
41+
background-color: white;
42+
box-shadow: 0px 2px 8px #888888;
43+
}
44+
45+
.fileManagement {
46+
margin: auto;
47+
display: flex;
48+
flex-direction: row;
49+
justify-content: space-around;
50+
align-items: center;
51+
position: relative;
52+
width: 100%;
53+
min-width: 500px;
54+
margin-top: 50px;
55+
font-family: sans-serif;
56+
}
57+
58+
.tree {
59+
position: relative;
60+
margin-top: 20px;
61+
padding-left: 45%;
62+
}

src/App.js

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import React, { Component } from 'react'
2+
import Dropzone from 'react-dropzone'
3+
import msgpack from 'msgpack-lite'
4+
5+
import ObjectNode from './Components/ObjectNode'
6+
import ArrayNode from './Components/ArrayNode'
7+
import NodeWrapper from './Components/NodeWrapper'
8+
import './App.css'
9+
10+
// let test = {
11+
// one: [
12+
// [
13+
// "test array",
14+
// "element two",
15+
// [
16+
// "third test"
17+
// ]
18+
// ],
19+
// "test string",
20+
// "a string",
21+
// {
22+
// test: "test object",
23+
// object: "another test"
24+
// },
25+
// 5
26+
// ]
27+
// }
28+
 
29+
class App extends Component {
30+
constructor (props) {
31+
super(props)
32+
33+
this.setValue = this.setValue.bind(this)
34+
this.download = this.genDownload()
35+
this.genContent = this.genContent.bind(this)
36+
this.parseData = this.parseData.bind(this)
37+
38+
this.isNumber = /^\d+$/
39+
this.isBool = /^(true|false)$/
40+
41+
this.state = {
42+
data: undefined,
43+
levelHeight: 30
44+
}
45+
46+
this.content = null
47+
}
48+
49+
setValue (key, value) {
50+
this.setState({ value })
51+
}
52+
53+
genContent (data) {
54+
const { levelHeight } = this.state
55+
const type = Array.isArray(data) ? 'array' : typeof data
56+
57+
switch (type) {
58+
case 'object':
59+
return (
60+
<NodeWrapper index={0} type={type} isRoot>
61+
<ObjectNode value={data} setValue={this.setValue} levelHeight={levelHeight} />
62+
</NodeWrapper>
63+
)
64+
case 'array':
65+
return (
66+
<NodeWrapper index={0} type={type} isRoot>
67+
<ArrayNode value={data} setValue={this.setValue} levelHeight={levelHeight} />
68+
</NodeWrapper>
69+
)
70+
default:
71+
return null
72+
}
73+
}
74+
75+
genDownload () {
76+
const a = document.createElement('a')
77+
document.body.appendChild(a)
78+
a.style = 'display:none'
79+
return (name) => {
80+
const { data } = this.state
81+
const parsed = this.parseData(data)
82+
const blob = new Blob([msgpack.encode(parsed)], { type: 'octete/stream' })
83+
const url = window.URL.createObjectURL(blob)
84+
a.href = url
85+
a.download = name
86+
a.click()
87+
window.URL.revokeObjectURL(url)
88+
}
89+
}
90+
91+
parseData (current) {
92+
if (typeof current === 'string') {
93+
if (this.isNumber.test(current))
94+
return Number(current)
95+
else if (this.isBool.test(current))
96+
return current === 'true'
97+
else
98+
return current
99+
}
100+
101+
if (Array.isArray(current)) {
102+
for (let i = 0; i < current.length; i++)
103+
current = current.map(this.parseData)
104+
} else {
105+
for (let key of Object.keys(current)) {
106+
current[key] = this.parseData(current[key])
107+
}
108+
}
109+
return current
110+
}
111+
112+
onDrop (files) {
113+
if (files.length === 0) return
114+
115+
const file = files[0]
116+
117+
const reader = new FileReader()
118+
reader.addEventListener('loadend', () => {
119+
const data = msgpack.decode(new Uint8Array(reader.result))
120+
this.content = this.genContent(data)
121+
this.setState({ data: undefined }, () => this.setState({ data }))
122+
})
123+
reader.readAsArrayBuffer(file)
124+
}
125+
126+
render() {
127+
const { data } = this.state
128+
129+
return (
130+
<div className="App">
131+
<div className='tree'>
132+
{this.genContent(data)}
133+
</div>
134+
<div className='fileManagement'>
135+
<button onClick={() => this.download('test.msp')}>
136+
<div className="downloadButton">
137+
<p>Download</p>
138+
</div>
139+
</button>
140+
<Dropzone onDrop={this.onDrop.bind(this)} className='dropzone' accept='.mp, .msp, .mpac'>
141+
<p>Try dropping some files here, or click to select files to upload.</p>
142+
</Dropzone>
143+
</div>
144+
</div>
145+
)
146+
}
147+
}
148+
149+
export default App

0 commit comments

Comments
 (0)