diff --git a/package.json b/package.json
index fa7a7a8..375eb77 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
"version": "1.0.0",
"dependencies": {
"electron-log": "^4.3.1",
+ "electron-store": "^7.0.2",
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
diff --git a/public/electron.js b/public/electron.js
index c73e287..e049a28 100644
--- a/public/electron.js
+++ b/public/electron.js
@@ -57,6 +57,7 @@ const createWindow = () => {
height: 600,
minWidth: 900,
minHeight: 600,
+ backgroundColor: '#0A826E',
});
// mainWindow.maximize();
mainWindow.show();
diff --git a/python/libs/iEEG.py b/python/libs/iEEG.py
index 7d1b7a4..9371e86 100644
--- a/python/libs/iEEG.py
+++ b/python/libs/iEEG.py
@@ -7,7 +7,7 @@
class Converter:
# data: {
- # file_path: '', // whee file located.
+ # file_path: '', // where file located.
# bids_directory: '', // where to output.
# read_only: true/false // read without write or write.
def __init__(self, data):
diff --git a/src/App.js b/src/App.js
index 8c45925..a1c5e81 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,4 +1,5 @@
-import React from 'react';
+import React, {useEffect, useState} from 'react';
+import {AppContext} from './context';
import './css/App.css';
// Socket.io
@@ -10,15 +11,85 @@ const options = {
// Components
import Welcome from './jsx/Welcome';
+import SplashScreen from './jsx/SplashScreen';
+import Converter from './jsx/Converter';
+import Menu from './jsx/elements/menu';
+// import {Authentication} from './jsx/elements/authentication';
/**
* App - the starting point.
* @return {JSX.Element}
*/
const App = () => {
+ const [appMode, setAppMode] = useState('SplashScreen');
+ const [activeMenuTab, setActiveMenuTab] = useState(0);
+
+ /**
+ * Similar to componentDidMount and componentDidUpdate.
+ */
+ useEffect(() => {
+ setTimeout(
+ () => {
+ setAppMode('Welcome');
+ }, 1500);
+ }, []);
+
return (
-
+ {
+ setAppMode(appMode);
+ },
+ }}>
+ <>
+
);
};
diff --git a/src/context.js b/src/context.js
new file mode 100644
index 0000000..0689019
--- /dev/null
+++ b/src/context.js
@@ -0,0 +1,6 @@
+import React from 'react';
+
+/**
+ * AppContext used as global state and init in App.js.
+ */
+export const AppContext = React.createContext({});
diff --git a/src/css/App.css b/src/css/App.css
index e69de29..b38b5a2 100644
--- a/src/css/App.css
+++ b/src/css/App.css
@@ -0,0 +1,19 @@
+html {
+ height: 100%;
+ -webkit-app-region: drag;
+ color: rgb(255, 255, 255);
+ background-color: rgb(10, 130, 110);
+}
+
+body {
+ margin: 0;
+ -webkit-app-region: drag;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+}
+
+.hidden {
+ display: none;
+}
diff --git a/src/css/Menu.css b/src/css/Menu.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/css/SplashScreen.css b/src/css/SplashScreen.css
new file mode 100644
index 0000000..440a88c
--- /dev/null
+++ b/src/css/SplashScreen.css
@@ -0,0 +1,27 @@
+.loader {
+ border: 8px solid #ffffff;
+ border-top: 8px solid #073e34;
+ border-left: 8px solid #073e34;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+}
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+.centered {
+ top: 50%;
+ left: 50%;
+ position: fixed;
+ margin-top: -30px;
+ margin-left: -45px;
+}
+.loader-font {
+ top: 50%;
+ left: 50%;
+ color: #ffffff;
+ font-size: 24px;
+ position: fixed;
+ margin: -120px 0 0 -110px;
+ font-family: "Bangla MN", serif;
+}
diff --git a/src/jsx/Converter.js b/src/jsx/Converter.js
new file mode 100644
index 0000000..9bec2b7
--- /dev/null
+++ b/src/jsx/Converter.js
@@ -0,0 +1,136 @@
+import React, {useContext, useState} from 'react';
+
+// Socket.io
+import {Event, SocketContext} from './socket.io';
+
+// Components
+import {DirectoryInput, FileInput, TextInput} from './elements/inputs';
+
+/**
+ * Converter - the iEEG to BIDS Converter component.
+ * @param {object} props
+ * @return {JSX.Element}
+ */
+const Converter = (props) => {
+ // React Context
+ const socketContext = useContext(SocketContext);
+
+ console.log('Converter rnedered');
+
+ // React State
+ const [edfFile, setEdfFile] = useState({});
+ const [bidsDirectory, setBidsDirectory] = useState(null);
+ const [siteID, setSiteID] = useState('');
+
+ const fireBidsConverter = () => {
+ socketContext.emit('ieeg_to_bids', {
+ file_path: edfFile.path,
+ bids_directory: bidsDirectory,
+ read_only: false,
+ });
+ };
+
+ const fireModifyBidsTsv = () => {
+ socketContext.emit('modify_bids_tsv', {
+ bids_directory: bidsDirectory,
+ site_id: siteID,
+ });
+ };
+
+ const onMessage = (message) => {
+ console.log(message);
+ };
+
+ const onUserInput = async (name, value) => {
+ if (name === 'edfFile') {
+ await setEdfFile(value);
+ } else if (name === 'bidsDirectory') {
+ await setBidsDirectory(value);
+ } else if (name === 'siteID') {
+ await setSiteID(value);
+ }
+ };
+
+ return (
+ <>
+
+ iEEG to BIDS Converter
+
+
+
+
+
+
+
+
+ 3. Convert file.edf to BIDS format:
+
+
+
+
+
+ Finalize participants.tsv for LORIS
+
+
+
+
+
+
+ 5. Modify participants.tsv data:
+
+
+
+
+ >
+ );
+};
+
+export default Converter;
diff --git a/src/jsx/SplashScreen.js b/src/jsx/SplashScreen.js
new file mode 100644
index 0000000..34607ca
--- /dev/null
+++ b/src/jsx/SplashScreen.js
@@ -0,0 +1,30 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import '../css/SplashScreen.css';
+
+/**
+ * Display the splash screen animation.
+ * @param {object} props
+ * @return {JSX.Element} - Loader React component
+ */
+const SplashScreen = (props) => {
+ return (
+ <>
+
+ PyCat is loading ...
+
+
+ >
+ );
+};
+SplashScreen.propTypes = {
+ size: PropTypes.string,
+};
+SplashScreen.defaultProps = {
+ size: '60',
+};
+
+export default SplashScreen;
diff --git a/src/jsx/Welcome.js b/src/jsx/Welcome.js
index 310fd81..fc2c9b1 100644
--- a/src/jsx/Welcome.js
+++ b/src/jsx/Welcome.js
@@ -1,10 +1,4 @@
-import React, {useContext, useState} from 'react';
-
-// Socket.io
-import {Event, SocketContext} from './socket.io';
-
-// Components
-import {DirectoryInput, FileInput, TextInput} from './elements/inputs';
+import React from 'react';
/**
* Welcome - the welcome component.
@@ -12,43 +6,6 @@ import {DirectoryInput, FileInput, TextInput} from './elements/inputs';
* @return {JSX.Element}
*/
const Welcome = (props) => {
- // React Context
- const socketContext = useContext(SocketContext);
-
- // React State
- const [edfFile, setEdfFile] = useState({});
- const [bidsDirectory, setBidsDirectory] = useState(null);
- const [siteID, setSiteID] = useState('');
-
- const fireBidsConverter = () => {
- socketContext.emit('ieeg_to_bids', {
- file_path: edfFile.path,
- bids_directory: bidsDirectory,
- read_only: false,
- });
- };
-
- const fireModifyBidsTsv = () => {
- socketContext.emit('modify_bids_tsv', {
- bids_directory: bidsDirectory,
- site_id: siteID,
- });
- };
-
- const onMessage = (message) => {
- console.log(message);
- };
-
- const onUserInput = async (name, value) => {
- if (name === 'edfFile') {
- await setEdfFile(value);
- } else if (name === 'bidsDirectory') {
- await setBidsDirectory(value);
- } else if (name === 'siteID') {
- await setSiteID(value);
- }
- };
-
return (
<>
{
cursor: 'default',
padding: '20px',
}}>
- iEEG to BIDS Converter
-
-
-
-
-
-
-
-
- 3. Convert file.edf to BIDS format:
-
-
-
-
-
- Finalize participants.tsv for LORIS
-
-
-
+ Welcome to pyCat!
-
-
- 5. Modify participants.tsv data:
-
-
+
+
Hello, you may begin your task by following the menu above.
+ Please remember to backup your data!
-
>
);
};
diff --git a/src/jsx/elements/authentication.js b/src/jsx/elements/authentication.js
new file mode 100644
index 0000000..fce6657
--- /dev/null
+++ b/src/jsx/elements/authentication.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export const Authentication = (props) => {
+ const handleClick = () => {
+ // Send current file to parent component
+ };
+ return (
+ <>
+
+ >
+ );
+};
+Authentication.propTypes = {
+ onUserInput: PropTypes.func,
+};
+
+export default {
+ Authentication,
+};
diff --git a/src/jsx/elements/menu.js b/src/jsx/elements/menu.js
new file mode 100644
index 0000000..6c2944f
--- /dev/null
+++ b/src/jsx/elements/menu.js
@@ -0,0 +1,103 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import '../../css/Menu.css';
+
+/**
+ * MenuTab - the menu tab component.
+ * @param {object} props
+ * @return {JSX.Element}
+ */
+const MenuTab = (props) => {
+ const styles = {
+ step: {
+ width: props.width,
+ padding: '0 0 2px 0',
+ position: 'relative',
+ display: 'table-cell',
+ WebkitUserSelect: 'none',
+ userSelect: 'none',
+ },
+ title: {
+ default: {
+ fontSize: 16,
+ color: 'black',
+ display: 'block',
+ fontWeight: '300',
+ cursor: 'pointer',
+ margin: '8px 0 0 0',
+ textAlign: 'center',
+ },
+ active: {
+ color: 'white',
+ },
+ },
+ };
+ const styleTitleText = {
+ ...styles.title.default,
+ ...(props.active ?
+ styles.title.active :
+ {}),
+ };
+ return (
+
+ );
+};
+MenuTab.propTypes = {
+ id: PropTypes.string,
+ title: PropTypes.string,
+ onClick: PropTypes.func,
+ active: PropTypes.bool,
+};
+
+/**
+ * Menu - the menu component.
+ * @param {object} props
+ * @return {JSX.Element}
+ */
+const Menu = (props) => {
+ const styles = {
+ root: {
+ padding: 0,
+ minHeight: 0,
+ width: '100%',
+ },
+ menu: {
+ width: '100%',
+ margin: '0 auto',
+ display: 'table',
+ },
+ };
+ return props.visible ? (
+
+
+ { props.tabs.map((tab, index) => (
+
+ ))}
+
+
+ ) : null;
+};
+Menu.defaultProps = {
+ activeTab: 0,
+};
+Menu.propTypes = {
+ visible: PropTypes.bool,
+ tabs: PropTypes.array,
+ activeTab: PropTypes.number,
+};
+
+export default Menu;