diff --git a/.prettierrc b/.prettierrc index 964f480..bca636c 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "tabWidth": 4, + "tabWidth": 2, "useTabs": true, "singleQuote": true } \ No newline at end of file diff --git a/package.json b/package.json index 2484762..58c5568 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,10 @@ "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@mui/icons-material": "^5.11.16", + "@mui/lab": "^5.0.0-alpha.134", "@mui/material": "^5.13.4", "axios": "^1.4.0", + "colorette": "^2.0.20", "electron": "^25.1.0", "electron-is-dev": "^2.0.0", "react": "^18.2.0", diff --git a/public/ascii.txt b/public/ascii.txt new file mode 100644 index 0000000..bad7e24 --- /dev/null +++ b/public/ascii.txt @@ -0,0 +1,16 @@ + .:-=-:. + .:=+++++++++=-. + :-=+++++++++++++++++=-: +=++++++++++++++++++++=:. +=+++++++++++++++=-: +=++++++++++++-. ###### ######## ######## ## ## ###### ## ## #### +=++++++++++++*+=:. ## ## ## ## ## ### ## ## ## ## ## ## +=++++++++++++******=-. ## ## ## ## #### ## ## ## ## ## +:=+++++++++++**********+- ###### ###### ######## ## ## ## ## #### ## ## ## + .:-+++++++********###* ## ## ## ## ## #### ## ## ## ## ## + :-=++***########* ## ## ## ## ## ## ### ## ## ## ## ## + .-*###########* ###### ######## ## ## ## ## ###### ####### #### + :=+###############* + .-=*###################* +.:=*#################*=-. + :=+#########+=: diff --git a/public/electron.js b/public/electron.js index 6bc0e9e..2ecedd4 100644 --- a/public/electron.js +++ b/public/electron.js @@ -1,6 +1,9 @@ const path = require('path'); const { app, BrowserWindow, dialog, ipcMain } = require('electron'); const isDev = require('electron-is-dev'); +const fs = require('fs'); +const colorette = require('colorette') +const { spawn } = require('node:child_process') function createWindow() { const mainWindow = new BrowserWindow({ @@ -41,7 +44,62 @@ function createWindow() { console.error(error); event.reply('folderData', []); }); - }); + }); + + ipcMain.on('submitForm', async (event, data) => { + // Process the submitted data here + console.log(`${colorette.green('✓')} Received sern init submit form data:`) + console.log(data); + console.log(`${colorette.cyan('🛈')} Current OS: ${currentOS}`) + + let packageManagerCommand + switch (data.chosenPackageManager) { + case 'npm': + packageManagerCommand = `npm create @sern/bot@latest -- --template=${data.chosenTemplate} --name="${data.projectName}" --install=npm` + break; + case 'yarn': + packageManagerCommand = `npm create @sern/bot@latest -- --template=${data.chosenTemplate} --name="${data.projectName}" --install=yarn` + break; + case 'pnpm': + packageManagerCommand = `npm create @sern/bot@latest -- --template=${data.chosenTemplate} --name="${data.projectName}" --install=pnpm` + break; + default: + packageManagerCommand = `npm create @sern/bot@latest -- --template=${data.chosenTemplate} --name="${data.projectName}"` + break; + } + let commandToRun + switch (currentOS) { + case 'linux': + commandToRun = `cd ${data.selectedPath};${packageManagerCommand}` + break; + case 'windows': + commandToRun = `cd /D ${data.selectedPath};${packageManagerCommand}` + break; + case 'macOS': + commandToRun = `cd ${data.selectedPath};${packageManagerCommand}` + break; + default: + // defaulting for linux (most probable command syntax) + commandToRun = `cd ${data.selectedPath};${packageManagerCommand}` + break; + } + + console.log(`${colorette.cyan('🛈')} About to execute command: ${commandToRun}`) + const cmd = spawn(commandToRun, { shell: true }) + + cmd.stdout.on('data', (data) => { + console.log(`${colorette.cyan('🛈')} Command stdout: ${data}`); + }); + + cmd.stderr.on('data', (data) => { + console.error(`${colorette.red('×')} Command stderr: ${data}`); + }); + + cmd.on('close', (code) => { + console.log(`${colorette.cyan('🛈')} Command exited with status code ${code}. Now notifying frontend...`); + event.reply('submitForm') + }); + }); } app.whenReady().then(createWindow); @@ -56,4 +114,23 @@ app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } -}); \ No newline at end of file +}); + +let currentOS +switch (process.platform) { + case 'linux': + currentOS = 'linux' + break; + case 'win32': + currentOS = 'windows' + break; + case 'darwin': + currentOS = 'macOS' + break; + default: + // defaulting for linux (most probable command syntax) + currentOS = 'linux' + break; +} + +console.log(fs.readFileSync(__dirname + '/ascii.txt', 'utf-8')) \ No newline at end of file diff --git a/src/InitModal.js b/src/InitModal.js index a22b945..a9cdb42 100644 --- a/src/InitModal.js +++ b/src/InitModal.js @@ -11,9 +11,9 @@ import TextField from '@mui/material/TextField'; import Checkbox from '@mui/material/Checkbox'; import FormGroup from '@mui/material/FormGroup'; import FormControlLabel from '@mui/material/FormControlLabel'; -import CardActions from '@mui/material/CardActions'; +import Alert from '@mui/material/Alert'; import './modalStyles.css'; -const { ipcRenderer } = window.require('electron') +const { ipcRenderer } = window.require('electron'); // eslint-disable-next-line no-unused-vars const style = { @@ -71,6 +71,11 @@ export default function InitModal() { ipcRenderer.send('openFolder'); }; + const [projectName, setProjectName] = React.useState(''); + const handleProjectNameChange = (event) => { + setProjectName(event.target.value); + }; + React.useEffect(() => { ipcRenderer.on('folderData', handleFolderData); @@ -84,99 +89,155 @@ export default function InitModal() { setSelectedPath(selectedPath); }; + const [loading, setLoading] = React.useState(false); + + const isFormValid = () => { + return projectName !== '' && selectedPath !== ''; + }; + + const handleSubmit = () => { + if (!isFormValid()) { + return; + } + + const data = { + projectName, + chosenTemplate, + installPackages, + chosenPackageManager, + selectedPath, + }; + + setLoading(true); + + ipcRenderer.send('submitForm', data); + + ipcRenderer.on('submitForm', () => { + setLoading(false); + handleClose(); + ipcRenderer.removeAllListeners('submitForm'); // Remove the listener to avoid memory leaks + }); + } + return ( -
- - - - - ~$ sern init - -
- - - - Select template - - - -
-
- - - } - fullWidth - label="Install packages while you're at it" - /> - - - - Select package manager - - - -
-
- - {/* - Selected directory: {selectedPath} - */} -
-
-
-
+
+ + + + + ~$ sern init + +
+ + + + Select template + + + +
+
+ + + } + fullWidth + label="Install packages while you're at it" + /> + + + + Select package manager + + + +
+
+ +
+
+ + {selectedPath ? `Selected directory: ${selectedPath}` : ''} + +
+
+ + Do not close the modal while it's loading. + +
+
+ +
+
+
+
); } diff --git a/src/modalStyles.css b/src/modalStyles.css index b1423a5..c888db0 100644 --- a/src/modalStyles.css +++ b/src/modalStyles.css @@ -32,4 +32,14 @@ display: flex; gap: 20px; margin-bottom: 20px; +} + +.bottomRight { + position: absolute; + right: 0; + bottom: 0; + width: 100%; + text-align: right; + margin-bottom: 40px; + margin-right: 40px; } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index eb2827d..e8d7547 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1851,6 +1851,20 @@ dependencies: "@babel/runtime" "^7.21.0" +"@mui/lab@^5.0.0-alpha.134": + version "5.0.0-alpha.134" + resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.134.tgz#e48c108fce91fbb89446dcf86ca35e7e761bc078" + integrity sha512-GhvuM2dNOi6hzjbeGEocWVozgyyeUn7RBmZhLFtniROauxmPCZMcTsEU+GAxmpyYppqHuI8flP6tGKgMuEAK/g== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/base" "5.0.0-beta.4" + "@mui/system" "^5.13.5" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.1" + clsx "^1.2.1" + prop-types "^15.8.1" + react-is "^18.2.0" + "@mui/material@^5.13.4": version "5.13.4" resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.13.4.tgz#1fed8249c980ed37f9767f9dba8aa3a589495ff3" @@ -1902,6 +1916,20 @@ csstype "^3.1.2" prop-types "^15.8.1" +"@mui/system@^5.13.5": + version "5.13.5" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.13.5.tgz#9f67ea0c4f6974713f90b7b94c999fd3f40f8de3" + integrity sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA== + dependencies: + "@babel/runtime" "^7.21.0" + "@mui/private-theming" "^5.13.1" + "@mui/styled-engine" "^5.13.2" + "@mui/types" "^7.2.4" + "@mui/utils" "^5.13.1" + clsx "^1.2.1" + csstype "^3.1.2" + prop-types "^15.8.1" + "@mui/types@^7.2.4": version "7.2.4" resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" @@ -3604,7 +3632,7 @@ colord@^2.9.1: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== -colorette@^2.0.10: +colorette@^2.0.10, colorette@^2.0.20: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==