diff --git a/electron-react/src/App.tsx b/electron-react/src/App.tsx index 0744f25..2f3b96a 100644 --- a/electron-react/src/App.tsx +++ b/electron-react/src/App.tsx @@ -1,22 +1,22 @@ // import Update from '@/components/update' -import React, { useContext, useEffect } from 'react'; -import Workshop from './pages/Workshop'; -import UIPage from './pages/UIPage'; -import { useUserComp } from './hooks/useContextHooks'; -import './App.scss'; -import FileExplorer from './components/FileExplorer/FileExplorer'; -import { ShowUIContext } from './components/context/ShowUIContext'; -import { motion } from 'framer-motion'; -import path from 'path'; -import fs from 'fs'; -import { PayloadType, UserActionType } from './components/context/ContextTypes'; -const os = require('os'); +import React, { useContext, useEffect } from "react"; +import Workshop from "./pages/Workshop"; +import UIPage from "./pages/UIPage"; +import { useUserComp } from "./hooks/useContextHooks"; +import "./App.scss"; +import FileExplorer from "./components/FileExplorer/FileExplorer"; +import { ShowUIContext } from "./components/context/ShowUIContext"; +import { motion } from "framer-motion"; +import path from "path"; +import fs from "fs"; +import { PayloadType, UserActionType } from "./components/context/ContextTypes"; +const os = require("os"); const pageVariants = { initial: { opacity: 0, y: 5, - scale: 0.9 + scale: 0.9, }, animate: { opacity: 1, @@ -26,39 +26,37 @@ const pageVariants = { type: "spring", stiffness: 800, damping: 100, - duration: 1 - } + duration: 1, + }, }, exit: { opacity: 0, y: -100, scale: 1.2, transition: { - duration: 1 - } - } + duration: 1, + }, + }, }; function App() { // for more info on useContext with typescript: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context - const contextVal = useContext(ShowUIContext) ?? { showUI: [null, null] } - const [showUIVal, setShowUIVal] = contextVal.showUI + const contextVal = useContext(ShowUIContext) ?? { showUI: [null, null] }; + const [showUIVal, setShowUIVal] = contextVal.showUI; const { components, dispatch } = useUserComp(); - useEffect(() => { - const filePath = path.join(os.homedir(), 'AthenaData123.json'); + const filePath = path.join(os.homedir(), "AthenaData123.json"); // Read the file's contents - fs.readFile(filePath, 'utf8', (err, data) => { + fs.readFile(filePath, "utf8", (err, data) => { if (err) { console.error(`Error reading file: ${err.message}`); } else { // Parse the JSON data const jsonData = JSON.parse(data); - console.log(jsonData); // Set user components - dispatch({ type: 'SET_COMPS', payload: jsonData }); + dispatch({ type: "SET_COMPS", payload: jsonData }); } }); }, []); @@ -71,14 +69,12 @@ function App() { initial="initial" animate="animate" exit="exit" - className='App' + className="App" > - ) - } - - else { + ); + } else { return ( - ) + ); } } -export default App +export default App; diff --git a/electron-react/src/assets/athenaJS.excalidraw b/electron-react/src/assets/athenaJS.excalidraw new file mode 100644 index 0000000..e69de29 diff --git a/electron-react/src/components/FileExplorer/DirectoryComponent.tsx b/electron-react/src/components/FileExplorer/DirectoryComponent.tsx index ff9f027..6f5a5d6 100644 --- a/electron-react/src/components/FileExplorer/DirectoryComponent.tsx +++ b/electron-react/src/components/FileExplorer/DirectoryComponent.tsx @@ -1,15 +1,19 @@ import React, { useState } from "react"; -import { Folder } from './FileExplorer'; +import { Folder } from "./FileExplorer"; interface DirectoryProps { name: string; files: Folder[]; fileParser: Function; path: string; - } -const DirectoryComponent: React.FC = ({ name, files, fileParser, path }) => { +const DirectoryComponent: React.FC = ({ + name, + files, + fileParser, + path, +}) => { // each directory component has access to it's name and files on property object // hook to tell whether button is opened or not const [isOpen, setOpen] = useState(false); @@ -18,13 +22,22 @@ const DirectoryComponent: React.FC = ({ name, files, fileParser, setOpen(!isOpen); }; - // TODO: readability refactor for recursive call return (
@@ -32,12 +45,16 @@ const DirectoryComponent: React.FC = ({ name, files, fileParser, {/* when isOpen is true, render all of the subfiles of the directory component */} {isOpen && (
-
+
{/* map over each subfile */} {files.map((file) => { - {/* generate subPath */} + { + /* generate subPath */ + } const subPath = `${path}/${file.name}`; // create a variable to store the path - {/* recursively render directory component with updated path, filename, and subfiles */} + { + /* recursively render directory component with updated path, filename, and subfiles */ + } return (
{file.directory ? ( diff --git a/electron-react/src/components/FileExplorer/FileExplorer.tsx b/electron-react/src/components/FileExplorer/FileExplorer.tsx index ad435dd..12fd921 100644 --- a/electron-react/src/components/FileExplorer/FileExplorer.tsx +++ b/electron-react/src/components/FileExplorer/FileExplorer.tsx @@ -1,35 +1,35 @@ -import { ipcRenderer } from 'electron'; -import React, { useState, useContext } from 'react'; -import DirectoryComponent from './DirectoryComponent'; -import { Resizable } from 're-resizable'; -import { useDetails } from '@/hooks/useContextHooks'; -import { motion } from 'framer-motion'; -import { FaFolderOpen } from 'react-icons/fa'; +import { ipcRenderer } from "electron"; +import React, { useState, useContext } from "react"; +import DirectoryComponent from "./DirectoryComponent"; +import { Resizable } from "re-resizable"; +import { useDetails } from "@/hooks/useContextHooks"; +import { motion } from "framer-motion"; +import { FaFolderOpen } from "react-icons/fa"; -const fs = window.require('fs'); -const pathModule = window.require('path'); +const fs = window.require("fs"); +const pathModule = window.require("path"); -import { parse } from '@babel/parser'; -const traverse = require('@babel/traverse').default; -import type { NodePath } from '@babel/traverse'; -const { Node } = require('@babel/types') +import { parse } from "@babel/parser"; +const traverse = require("@babel/traverse").default; +import type { NodePath } from "@babel/traverse"; +const { Node } = require("@babel/types"); const containerVariants = { hidden: { - x: '-5rem', + x: "-5rem", }, visible: { x: 0, transition: { - type: 'spring', + type: "spring", stiffness: 2000, damping: 100, }, }, exit: { - x: '-77%', + x: "-77%", transition: { - type: 'spring', + type: "spring", stiffness: 700, damping: 100, }, @@ -38,9 +38,9 @@ const containerVariants = { // might move to it's own type file export interface Folder { - name: string; + name: string; path: string; - directory: boolean, + directory: boolean; files: Folder[]; } @@ -59,18 +59,17 @@ const FileExplorer: React.FC = () => { const [explorerVisible, setExplorerVisible] = useState(false); // sets CSS to transition sidebar to close - const sidebarClass = explorerVisible ? 'sidebar' : 'sidebar-closed'; + const sidebarClass = explorerVisible ? "sidebar" : "sidebar-closed"; const handleToggle = () => { setExplorerVisible(!explorerVisible); }; const handleOpenFolder = (): void => { // open folder - const directory: string[] = ipcRenderer.sendSync('OpenFolder'); - // console.log("DIRECTORY HERE!!!: ", directory); + const directory: string[] = ipcRenderer.sendSync("OpenFolder"); let directoryPath = directory[0]; // accounting for windows backslash to normalize the path - directoryPath = directoryPath.replace(/\\/g, '/'); + directoryPath = directoryPath.replace(/\\/g, "/"); // generate first level of file tree const firstLevelFileTree = directoryToFolderMapper(directoryPath); // generate full tree @@ -80,14 +79,13 @@ const FileExplorer: React.FC = () => { setUploadedFiles(uploadedFileComponents); }; - const directoryToFolderMapper = (directoryPath: string): Folder[] => { - // console.log("DIRECTORY PATH: ", directoryPath); + const directoryToFolderMapper = (directoryPath: string): Folder[] => { const pathToFilesFolders: string[] = fs.readdirSync(directoryPath); // temp any // filter pathToFilesFolders for node modules or git files const filesAndFolders = pathToFilesFolders //using type inference since we know files in pathToFilesFolders are strings, so all 'filename' args should already be strings .filter((filename) => { - return filename !== 'node_modules' && filename !== '.git'; + return filename !== "node_modules" && filename !== ".git"; }) // map over each filename, instead returning object that has name, directory, and filename's properties // ['src', 'index'] @@ -96,7 +94,6 @@ const FileExplorer: React.FC = () => { const subPath = pathModule.join(directoryPath, filename); const stats = fs.statSync(subPath); - // console.log(stats); return { name: filename, path: subPath, @@ -163,13 +160,12 @@ const FileExplorer: React.FC = () => { }; //This function allows us to parse files in order to populate our text areas within PropsWindow.jsx - function parseAndTraverseAST (dataString: string): void { - + function parseAndTraverseAST(dataString: string): void { //Initialize two empty arrays to store parsed function declarations and JSX returns const componentBodyArray: string[] = []; const JSXArray: string[] = []; - //Initialize a bool flag to track whether or not there is JSX within a function + //Initialize a bool flag to track whether or not there is JSX within a function let isJSX = false; //This object defines a vistor for traversing nested JSX elements with a function declaration @@ -177,69 +173,74 @@ const FileExplorer: React.FC = () => { const nestedJSXVisitor = { JSXElement(path: any) { isJSX = true; - - // Extract the string representation of the JSX element - const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; }, }; + //Define a helper function to slice our data string at the start and end of our path node + const stringSliceAndPush = (array: string[], path: any): void => { + const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; + array.push(parsedStr); + }; + //Use Babel to parse the input codee string into an Abstract Syntax Tree (AST) - const ast = parse(dataString, { sourceType: 'module', plugins: ['jsx', 'flow'],}); + const ast = parse(dataString, { + sourceType: "module", + plugins: ["jsx", "flow"], + }); //Traverse the AST using the visitor pattern to extract function declarations and JSX Elements nested within return statements traverse(ast, { enter(path: any) { - if(path.isCallExpression()) { - if(path.node.callee.name === 'useEffect') { - const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; - componentBodyArray.push(parsedStr); + if (path.isCallExpression()) { + if (path.node.callee.name === "useEffect") { + stringSliceAndPush(componentBodyArray, path); } } if (path.isFunctionDeclaration()) { //Traverse any nested JSX elements within the function declaration using the nestedJSXVisitor path.traverse(nestedJSXVisitor); - //If the function declaration does not contain JSX, extract its string representation - if(isJSX === false) { - const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; - componentBodyArray.push(parsedStr); + //If the function declaration does not contain JSX, extract its string representation + if (isJSX === false) { + stringSliceAndPush(componentBodyArray, path); } - //Reset the isJSX bool flag for the next function declaration + //Reset the isJSX bool flag for the next function declaration isJSX = false; } if (path.isVariableDeclaration()) { - if(path.node.declarations[0].init.type === 'ArrowFunctionExpression') { - + if ( + path.node.declarations[0].init.type === "ArrowFunctionExpression" + ) { //Traverse any nested JSX elements within the arrow function expression using the nestedJSXVisitor again path.traverse(nestedJSXVisitor); - + //If the arrow function does not contain JSX, extract its string representation - if(isJSX === false) { - const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; - componentBodyArray.push(parsedStr); + if (isJSX === false) { + stringSliceAndPush(componentBodyArray, path); } // Reset the isJSX flag for the next arrow function expression isJSX = false; } else { // Parses normal variable declarations - const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; - componentBodyArray.push(parsedStr); + stringSliceAndPush(componentBodyArray, path); } } - //This conditional checks for JSX content as well as checks if the JSX's parent is a return statement. + // This conditional checks for JSX content as well as che zcks if the JSX's parent is a return statement. if (path.isJSXElement() && path.parentPath.isReturnStatement()) { - const parsedStr = `${dataString.slice(path.node.start, path.node.end)}`; - JSXArray.push(parsedStr); + stringSliceAndPush(JSXArray, path); + } + if (path.isJSXFragment() && path.parentPath.isReturnStatement()) { + stringSliceAndPush(JSXArray, path); } }, }); - //Concatenate the parsed function declarations into a single string and save it to a state variable - let componentBodyString = ''; + //Concatenate the parsed function declarations into a single string and save it to a state variable + let componentBodyString = ""; // purpose of this function: - // previously, variables and functions within useEffectHook would be duplicated in component body window - // this function filters all elements that are contained within other elements - // with this, all functions or variables within a useEffect hook will only be printed once. + // previously, variables and functions within useEffectHook would be duplicated in component body window + // this function filters all elements that are contained within other elements + // with this, all functions or variables within a useEffect hook will only be printed once. function filterDuplicateFunctions(arr: string[]): string[] { return arr.filter((el, index) => { const otherEls = arr.slice(0, index).concat(arr.slice(index + 1)); @@ -255,42 +256,40 @@ const FileExplorer: React.FC = () => { (acc, curr) => acc + "\n" + "\n" + curr ); setTempCompBodyVal(componentBodyString); - - //Concatenate the parsed JSX elements into a single string and save it to a state variable - const JSXString = JSXArray.reduce((acc, curr) => acc + '\n' + '\n' + curr); + + //Concatenate the parsed JSX elements into a single string and save it to a state variable + const JSXString = JSXArray.reduce((acc, curr) => acc + "\n" + "\n" + curr); setTempCompJSXVal(JSXString); } const fileParser = (path: string): void => { // asynchronously read file here passing in the absolute path. // data is a string - fs.readFile(path, "utf-8", (err: NodeJS.ErrnoException | null, data: string) => { - //declare variable extension which gets the extension of our file i.e. .jsx - const extension = pathModule.extname(path).toLowerCase(); - try { - switch(extension) { - case '.jsx': - parseAndTraverseAST(data); - break; - - case '.js': - console.log('JS File content:', data); - break; - case '.css': - console.log('CSS File content:', data); - break; - default: - console.log('File data:', data); + fs.readFile( + path, + "utf-8", + (err: NodeJS.ErrnoException | null, data: string) => { + //declare variable extension which gets the extension of our file i.e. .jsx + const extension = pathModule.extname(path).toLowerCase(); + try { + // left as switch statement for extension more file cases + switch (extension) { + case ".jsx": + parseAndTraverseAST(data); + break; + default: + console.log("File data:", data); + } + } catch (err) { + //handle errors + console.log( + "ERROR: error reading file in DirectoryComponent.jsx:", + err + ); + return; } - } catch (err) { - //handle errors - console.log( - "ERROR: error reading file in DirectoryComponent.jsx:", - err - ); - return; } - }); + ); }; return ( diff --git a/electron-react/src/components/Navigation/NavBar.tsx b/electron-react/src/components/Navigation/NavBar.tsx index 5befebb..ce0bf4f 100644 --- a/electron-react/src/components/Navigation/NavBar.tsx +++ b/electron-react/src/components/Navigation/NavBar.tsx @@ -1,7 +1,7 @@ import React, { useContext, useState } from 'react'; import { motion } from 'framer-motion'; import { NavBarProps, handleToggleWindow } from './NavTypes' -import { useShowUI } from '@/hooks/useContextHooks'; +import { useShowUI } from '../../hooks/useContextHooks'; const NavBar: React.FC = ({handleToggleWindow}) => { diff --git a/electron-react/src/components/Navigation/NavBarUI.tsx b/electron-react/src/components/Navigation/NavBarUI.tsx index 449cdb7..0f19f79 100644 --- a/electron-react/src/components/Navigation/NavBarUI.tsx +++ b/electron-react/src/components/Navigation/NavBarUI.tsx @@ -1,7 +1,7 @@ import React, { useContext, useState } from 'react'; import { ShowUIContext } from '../context/ShowUIContext'; import { motion } from 'framer-motion'; -import { useShowUI } from '@/hooks/useContextHooks'; +import { useShowUI } from '../../hooks/useContextHooks'; const NavBarUI: React.FC = () => { diff --git a/electron-react/src/components/Navigation/NavigationContainer.tsx b/electron-react/src/components/Navigation/NavigationContainer.tsx index e4e6b2e..0d26bac 100644 --- a/electron-react/src/components/Navigation/NavigationContainer.tsx +++ b/electron-react/src/components/Navigation/NavigationContainer.tsx @@ -1,16 +1,16 @@ -import React, { useContext, useState } from 'react'; -import PropsWindow from '../WorkshopMain/PropsWindow'; -import NavBar from './NavBar'; -import PerformanceCharts from '../WorkshopMain/PerformanceCharts'; -import SavedComps from '../WorkshopMain/SavedComps'; -import { NavigationContainerProps, handleToggleWindow } from './NavTypes'; - +import React, { useContext, useState } from "react"; +import PropsWindow from "../WorkshopMain/PropsWindow"; +import NavBar from "./NavBar"; +import PerformanceCharts from "../WorkshopMain/PerformanceCharts"; +import SavedComps from "../WorkshopMain/SavedComps"; +import { NavigationContainerProps, handleToggleWindow } from "./NavTypes"; const NavigationContainer: React.FC = () => { const [showPropsWindow, setShowPropsWindow] = useState(true); - const [showPerformanceCharts, setShowPerformanceCharts] = useState(false); + const [showPerformanceCharts, setShowPerformanceCharts] = + useState(false); const [showSavedComps, setShowSavedComps] = useState(false); - // console.log(`logs are in NavigationContainer: ${logs}`); + const handleToggleWindow: handleToggleWindow = { props: (e) => { setShowPropsWindow(true); @@ -26,19 +26,19 @@ const NavigationContainer: React.FC = () => { setShowSavedComps(true); setShowPerformanceCharts(false); setShowPropsWindow(false); - } + }, }; return (