├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── buildApp.yml │ └── tests.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── electron-react ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .vscode │ ├── .debug.script.mjs │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── athena-website │ ├── .gitignore │ ├── README.md │ ├── babel.config.js │ ├── blog │ │ ├── 2019-05-28-first-blog-post.md │ │ ├── 2019-05-29-long-blog-post.md │ │ ├── 2021-08-01-mdx-blog-post.mdx │ │ ├── 2021-08-26-welcome │ │ │ ├── docusaurus-plushie-banner.jpeg │ │ │ └── index.md │ │ └── authors.yml │ ├── docs │ │ ├── UI-mode │ │ │ ├── _category_.json │ │ │ ├── img │ │ │ │ ├── docsVersionDropdown.png │ │ │ │ └── localeDropdown.png │ │ │ └── manage-docs-versions.md │ │ ├── editing-your-component │ │ │ ├── _category_.json │ │ │ ├── defining-actions.md │ │ │ ├── mocking-props.md │ │ │ ├── mocking-state.md │ │ │ └── rendering-component.md │ │ ├── intro.md │ │ └── tutorial-basics │ │ │ ├── _category_.json │ │ │ ├── congratulations.md │ │ │ ├── create-a-blog-post.md │ │ │ ├── create-a-document.md │ │ │ ├── create-a-page.md │ │ │ ├── deploy-your-site.md │ │ │ └── markdown-features.mdx │ ├── docusaurus.config.js │ ├── package.json │ ├── sidebars.js │ ├── src │ │ ├── components │ │ │ └── HomepageFeatures │ │ │ │ ├── index.js │ │ │ │ └── styles.module.css │ │ ├── css │ │ │ └── custom.css │ │ └── pages │ │ │ ├── index.js │ │ │ ├── index.module.css │ │ │ └── markdown-page.md │ ├── static │ │ ├── .nojekyll │ │ └── img │ │ │ ├── athenaFull_transparent.jpg │ │ │ ├── athena_icon_whitebg.png │ │ │ ├── athenajs-social-card.psd │ │ │ ├── athenajs_social_card.png │ │ │ ├── docusaurus-social-card.jpg │ │ │ ├── docusaurus.png │ │ │ ├── favicon.ico │ │ │ ├── logo.svg │ │ │ ├── navbar_logo_dark.png │ │ │ ├── navbar_logo_light.png │ │ │ ├── undraw_docusaurus_mountain.svg │ │ │ ├── undraw_docusaurus_react.svg │ │ │ └── undraw_docusaurus_tree.svg │ └── tsconfig.json ├── babel.config.js ├── build │ ├── icon.icns │ └── icon.png ├── electron-builder.json5 ├── electron │ ├── electron-env.d.ts │ ├── main │ │ ├── index.ts │ │ └── update.ts │ └── preload │ │ └── index.ts ├── index.html ├── jest.config.js ├── package.json ├── playwright.config.ts ├── src │ ├── App.scss │ ├── App.tsx │ ├── assets │ │ ├── Athena_Icon.png │ │ ├── Icon-1024.png │ │ ├── Icon-128.png │ │ ├── Icon-256.png │ │ ├── Icon-32.png │ │ ├── Icon-64.png │ │ ├── athenaJS.excalidraw │ │ ├── athena_logo01.png │ │ ├── logo_whitebg.png │ │ └── node.svg │ ├── components │ │ ├── FileExplorer │ │ │ ├── DirectoryComponent.tsx │ │ │ └── FileExplorer.tsx │ │ ├── Navigation │ │ │ ├── NavBar.tsx │ │ │ ├── NavBarUI.tsx │ │ │ ├── NavContainerUI.tsx │ │ │ ├── NavTypes.ts │ │ │ ├── NavigationContainer.tsx │ │ │ └── __tests__ │ │ │ │ ├── NavBar.test.jsx │ │ │ │ └── NavBarUI.test.jsx │ │ ├── UIWindow │ │ │ ├── ReactFlowComp.tsx │ │ │ ├── UIComps.tsx │ │ │ ├── UITypes.ts │ │ │ ├── ViewUI.tsx │ │ │ └── __tests__ │ │ │ │ └── UIComps.test.jsx │ │ ├── WorkshopMain │ │ │ ├── PerformanceCharts.tsx │ │ │ ├── PropsWindow.tsx │ │ │ ├── SavedComps.tsx │ │ │ ├── ViewComponent.tsx │ │ │ ├── WorkshopTypes.ts │ │ │ └── __tests__ │ │ │ │ ├── PerformanceCharts.test.jsx │ │ │ │ ├── SavedComps.test.jsx │ │ │ │ └── ViewComponent.test.jsx │ │ ├── context │ │ │ ├── ContextTypes.ts │ │ │ ├── DetailsContext.tsx │ │ │ ├── MockFetchContext.tsx │ │ │ ├── PerformanceContext.tsx │ │ │ ├── ShowUIContext.tsx │ │ │ └── UserCompContext.tsx │ │ ├── framerMotion │ │ │ ├── AthenaLogo.jsx │ │ │ └── AthenaSvg.jsx │ │ └── update │ │ │ ├── Modal │ │ │ ├── index.tsx │ │ │ └── modal.module.scss │ │ │ ├── Progress │ │ │ ├── index.tsx │ │ │ └── progress.module.scss │ │ │ ├── electron-updater.d.ts │ │ │ ├── index.tsx │ │ │ └── update.module.scss │ ├── data │ │ └── data.json │ ├── hooks │ │ └── useContextHooks.tsx │ ├── main.tsx │ ├── pages │ │ ├── UIPage.jsx │ │ └── Workshop.jsx │ ├── samples │ │ └── node-api.ts │ └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── vite.legacy.config.ts └── package-lock.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/buildApp.yml: -------------------------------------------------------------------------------- 1 | name: PR CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - dev 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [16.x] 17 | 18 | steps: 19 | - name: Checkout code 20 | uses: actions/checkout@v3 21 | with: 22 | ref: ${{ github.ref }} 23 | fetch-depth: 0 24 | 25 | - name: List files in electron-react directory 26 | run: ls -la 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v3 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | 33 | - name: Install dependencies 34 | run: npm install 35 | working-directory: './electron-react' # run npm ci in electron-react directory 36 | 37 | - name: Build project 38 | run: npm run build --if-present 39 | working-directory: './electron-react' # run npm run build in electron-react directory 40 | 41 | - name: Run tests 42 | run: npm test 43 | working-directory: './electron-react' # run npm test in electron-react directory 44 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - '' 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | node-version: [16.x] 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v3 19 | with: 20 | ref: ${{ github.ref }} 21 | fetch-depth: 0 22 | 23 | - name: List files in electron-react directory 24 | run: ls -la 25 | 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | 31 | - name: Install dependencies 32 | run: npm install 33 | working-directory: './electron-react' # run npm ci in electron-react directory 34 | 35 | - name: Run tests 36 | run: npm test 37 | working-directory: './electron-react' # run npm test in electron-react directory 38 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | athenajsdev@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 |

4 | Setup 5 | | 6 | File Structure 7 | | 8 | Iteration Roadmap 9 |

10 | 11 | If you're reading this document, we're really excited that you want to contribute to the project! All work on AthenaJS happens directly on GitHub. If you would like to contribute, please send a pull request to the dev branch. The following guide has some useful information, so we highly recommend you take a look at it before getting started! 12 | 13 | ## Code of Conduct 14 | 15 | We expect contributors to adhere to our code of conduct. Please read the full text so that you can understand what actions are expected of contributors to the project. 16 | 17 | ## Not sure where to start? 18 | 19 | - You'll most likely need to read up on a few tools and libraries 20 | - [React Live](https://github.com/FormidableLabs/react-live) 21 | - Used to render components 22 | - [React Flow](https://reactflow.dev/docs/quickstart/) 23 | - Enables the drag and drop UI prototyping tool with custom nodes 24 | - [Styled Components](https://styled-components.com/docs) 25 | - Styling components within the app is primarily done using the Styled Components Library 26 | - [Fetch Mock](https://www.wheresrhys.co.uk/fetch-mock/) 27 | - Used to set up a mock server 28 | - Parsing user uploaded files 29 | - [ASTs](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (Abstract Syntax Tree): 30 | - We use Babel for parsing and traversing user uploaded files: the Babel AST [spec](https://github.com/babel/babel/blob/main/packages/babel-parser/ast/spec.md) is a bit different from [ESTree](https://github.com/estree/estree). 31 | - Check out [the Babel Plugin Handbook](https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md#babel-plugin-handbook), in particular the parser, traverser, and best practices section 32 | - Check out [AST Explorer](http://astexplorer.net/#/scUfOmVOG5) to learn more about ASTs 33 | - testing with [Jest](https://jestjs.io/docs/getting-started) 34 | - [Mocking React Context](https://polvara.me/posts/mocking-context-with-react-testing-library) 35 | 36 | - Helpful diagrams 37 | - [Athena App Diagram (Excalidraw)](#) 38 |
39 | 40 | ### Setup 41 | 42 | If you want to contribute to AthenaJS, the first step is to fork and clone the repository to your local machine. Once you've cloned it, navigate to the "electron-react" folder and run "npm run dev" to start up the application after installing the dependencies. This will allow you to begin making changes and testing your code. 43 | 44 | ```sh 45 | git clone https://github.com/oslabs-beta/Athena.git 46 | cd Athena/electron-react 47 | ``` 48 | 49 | Then you can run: 50 | 51 | ```sh 52 | npm run dev 53 | ``` 54 | Which will spin up the application on your local machine. AthenaJS uses Vite for an enhanced development experience with really fast HMR. Any changes you make to the codebase on your local machine will be quickly reflected on your running instance of AthenaJS! 55 | 56 | ## File Structure 57 | 58 | - Electron React (Root Directory for AthenaJS Project) 59 | - Electron (Electron) 60 | - Main (Electron-main) 61 | - Preload (Pre-load scripts) 62 | - src (React) 63 | - Index.tsx (Hangs app off of root and wraps app in context providers) 64 | - App.tsx 65 | - Pages 66 | - UI Page 67 | - Workshop 68 | - Components 69 | - Components are grouped by category 70 | - Accompanying tests should be placed in a __test__ folder next to the components they are unit testing 71 | - Files containing TypeScript Types used for components are located in the same category folder as the components 72 | 73 | ## Iteration Roadmap 74 | 75 | Not sure what contribution you want to make? Here are a few starting points: 76 | 77 | 1. Add unit tests with Jest. We are continually adding unit tests for components in order to enhance the quality and reliability of the codebase. 78 | - If you notice tests are missing for a component, we welcome additions to the testing ecosystem of AthenaJS! 79 | - If you make a pull request with a new component, consider adding an accompanying test file 80 | 2. Adding support for class components 81 | 3. Adding support for components written in TypeScript 82 | 4. Adding Tailwind CSS support for styling components 83 | 84 | ## License 85 | By contributing to AthenaJS, you agree that your contributions will be licensed under its MIT license. 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 OSLabs Beta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | AthenaJS Logo 4 | 5 |

6 | 7 | 8 | 9 | [![MIT License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge)](https://github.com/oslabs-beta/Athena/blob/main/LICENSE) 10 | 11 |
12 | 13 | ![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB)    14 | ![Electron.js](https://img.shields.io/badge/Electron-191970?style=for-the-badge&logo=Electron&logoColor=white)    15 | ![Vite](https://img.shields.io/badge/vite-%23646CFF.svg?style=for-the-badge&logo=vite&logoColor=white) 16 | 17 |
18 | 19 | ![TypeScript](https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white)    20 | ![SASS](https://img.shields.io/badge/SASS-hotpink.svg?style=for-the-badge&logo=SASS&logoColor=white)    21 | ![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white) 22 | 23 | [![Join us on Discord](https://img.shields.io/badge/Join%20us%20on%20Discord-7289DA?logo=discord&logoColor=white)](https://discord.gg/6xkMNXtBYp) 24 | 25 | 26 |
27 |
28 | 29 |

30 | Features 31 | • 32 | Questions 33 | • 34 | Contributing 35 | • 36 | Read More 37 | • 38 | The Team 39 |

40 | 41 |
42 | 43 | ## What is AthenaJS? 44 | 45 | AthenaJS is a component visualizer workshop that allows developers to quickly develop and edit their React 46 | components in isolation without codebase integration. 47 | 48 | **Easy to use**: AthenaJS is a standalone electron application that allows developers to import their 49 | own React components or create components from scratch within the application's code editor. 50 | 51 | **Dynamic**: Developers can mock HTTP requests, style, and change the functionality of their components within the application's code editors. Changes are reflected in the renderer with the press of a button! 52 | 53 | **UI Mode**: After developers have created/edited their react components, they can navigate to the UI Mode section and prototype UIs using components from their library. 54 | 55 |
56 | 57 | ## Documentation & Installation 58 | 59 | You can find documentation and download the app on our website 60 | 61 | If you just want to download the app, you can find it under "Releases" on the right-hand side of GitHub! 62 | 63 | **Mac users**: The application needs to be approved in the "Security and Privacy" tab before it can be run. 64 | 65 |
66 | 67 | ## Features 68 | 69 | Interested in what you can do with AthenaJS? Here is a quick summary of all the great features you can start developing with! 70 | 71 | Please note AthenaJS only works for ***functional components***, but work is currently being done to add support for class components! 72 | 73 | ### Developing a Component from Scratch 74 | 75 | https://user-images.githubusercontent.com/35904733/230973355-08ee1f98-7428-48ec-9b7a-d8a31f8cd1d2.mov 76 | 77 |
78 | 79 | 💠 You can develop components from scratch and export them to your React project using our code editors! The JSX editor holds the return statement of the component and the body contains everything else (your hooks, functions, etc.). Press update view to view your changes live in the component renderer. Save your progress by choosing a name for your component and saving it to the component library. 80 | 81 | ### Upload and Edit Components 82 | 83 | https://user-images.githubusercontent.com/35904733/230982140-5f46aa3d-eb19-4bde-be6c-f82d078a858e.mov 84 | 85 |
86 | 87 | 💠 If you already have components built for your project and want to edit them, open the file explorer and import any of your React components! Our parser will inject your code into the editors so you can get started easily. Simply define any props your component relies on in the body editor and update the view to get your component working in the app! 88 | 89 | ### Fetch Mock Integration 90 | 91 | https://user-images.githubusercontent.com/35904733/230982230-daf91647-7ccb-4ff0-b57f-6e0ce4dc4567.mov 92 | 93 |
94 | 95 | 💠 If your component makes an http request with fetch, AthenaJS includes feck-motch integration to mock the response. If you are interested in all of the great features available to you with feck-motch, check out the documentation . By default, our settings intercept all requests and respond with an object {data: 'mock data'} to get you started quickly. 96 | 97 | ### Styling Your Components 98 | 99 | https://user-images.githubusercontent.com/35904733/230982240-82f1cc69-ff5b-49c7-aa61-be5cfd357268.mov 100 | 101 |
102 | 103 | 💠 AthenaJS includes styled-components integration, check out the documentation here to get started. Styled components lets you write actual CSS code to style your components, so you can get started quick and easy! Declare your styled component variable in the body editor and write CSS or copy over code from your CSS file to quickly style your component! 104 | 105 | ### Compare Component Render Times 106 | 107 | https://user-images.githubusercontent.com/35904733/230982261-e5e4f161-35d0-4cfb-a17d-f2e5feda18f6.mov 108 | 109 |
110 | 111 | 💠 Curious which components are causing or have the potential to cause a bottleneck in your application? Every time you render a new component, the render time is captured using the React Profiler API, the same API that React Dev Tools are built on. Render times can be added to a bar graph with the click of a button to easily compare render times across different components. 112 | 113 | ### Save Components 114 | 115 | https://user-images.githubusercontent.com/35904733/230982276-2df23884-b1c8-4d6c-bc5d-93f6ff4173f1.mov 116 | 117 |
118 | 119 | 💠 Press 'Save Library' to save your component library to your home directory. Your components will be persisted between sessions, so you can easily pick up from where you left off. Render any of your components and make changes to them, delete them from your library, or export them as a jsx file to easily integrate the components you develop into your React projects. 120 | 121 | ### UI Whiteboard 122 | 123 | https://user-images.githubusercontent.com/35904733/230982285-5e3f8933-2ca8-49a4-a995-e42e5acd0fe8.mov 124 | 125 |
126 | 127 | 💠 Once you build a component library, you can easily prototype UIs using the drag and drop UI whiteboard. The whiteboard area can be saved as a screenshot to your downloads folder by pressing the screenshot button on the top right portion of the screen. 128 | 129 | 💠 One of the team's favorite uses of this tool is to compare similar components. Not sure which navbar or button you like best? Add them to the whiteboard and compare them side-by-side! 130 | 131 | 132 |
133 | 134 | ## Questions and Support 135 | 136 | If you have any questions or need help with the project, please don't hesitate to ask! You can reach out to us on [Discord](https://discord.gg/6xkMNXtBYp) or [create an issue](https://github.com/oslabs-beta/Athena/issues/new/choose) on this repo. 137 | 138 |
139 | 140 | ## Contributing 141 | 142 | Navigate to the [CONTRIBUTING.md](CONTRIBUTING.md) file to learn how you can contribute to AthenaJS! 143 | 144 |
145 | 146 | ## Read More 147 | 148 | Check out our Medium article to read more! 149 | 150 |
151 | 152 | ## The Team 153 | 154 | ***AthenaJS Core Team*** 155 | 156 | | Developed By | Github | LinkedIn | 157 | | :------------------: | :-------------: | :-------------: | 158 | | Christopher Long | [![Github](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/cvalong) | [![LinkedIn](https://img.shields.io/badge/LinkedIn-%230077B5.svg?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/cvalong) | 159 | | Daniel Chang | [![Github](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Chang254) | [![LinkedIn](https://img.shields.io/badge/LinkedIn-%230077B5.svg?logo=linkedin&logoColor=white)](www.linkedin.com/in/daniel-k-chang) | 160 | | Derrick Oh | [![Github](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Igniphis) | [![LinkedIn](https://img.shields.io/badge/LinkedIn-%230077B5.svg?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/derrickjoh/) | 161 | | Matthew Fukudome | [![Github](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/mattfookoo) | [![LinkedIn](https://img.shields.io/badge/LinkedIn-%230077B5.svg?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/matthewfukudome/) | 162 | | Ryan Motamen | [![Github](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/ryanmotamen) | [![LinkedIn](https://img.shields.io/badge/LinkedIn-%230077B5.svg?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/ryan-motamen/) | 163 |
164 | Special thanks to our friend Michelle for the logo and icon design! 165 |
166 | 167 | ## How is the repo structured? 168 | 169 | The Athena JS repo is managed as a monorepo check out the [CONTRIBUTING.md](CONTRIBUTING.md) for development and check here for the doc website. 170 | 171 |
172 | 173 | ## License 174 | 175 | Athena is [MIT licensed](https://github.com/oslabs-beta/Athena/blob/main/LICENSE). 176 | 177 |
178 | -------------------------------------------------------------------------------- /electron-react/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "root": true, 3 | "ignorePatterns": ["**/test", "**/__tests__"], 4 | "env": { 5 | "node": true, 6 | "browser": true, 7 | "es2021": true 8 | }, 9 | "plugins": ["react"], 10 | "extends": ["eslint:recommended", "plugin:react/recommended"], 11 | "parserOptions": { 12 | "sourceType": "module", 13 | "ecmaFeatures": { 14 | "jsx": true 15 | } 16 | }, 17 | "rules": { 18 | "indent": ["warn", 2], 19 | "no-unused-vars": ["off", { "vars": "local" }], 20 | "no-case-declarations": "off", 21 | "prefer-const": "warn", 22 | "quotes": ["warn", "single"], 23 | "react/prop-types": "off", 24 | "semi": ["warn", "always"], 25 | "space-infix-ops": "warn" 26 | }, 27 | "settings": { 28 | "react": { "version": "detect"} 29 | } 30 | }; 31 | 32 | 33 | -------------------------------------------------------------------------------- /electron-react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | dist-electron 14 | release 15 | *.local 16 | 17 | # Editor directories and files 18 | .vscode/.debug.env 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | 27 | #lockfile 28 | package-lock.json 29 | pnpm-lock.yaml 30 | yarn.lock 31 | /test-results/ 32 | /playwright-report/ 33 | /playwright/.cache/ 34 | 35 | #Zone identifier 36 | *.Zone.Identifier -------------------------------------------------------------------------------- /electron-react/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true -------------------------------------------------------------------------------- /electron-react/.vscode/.debug.script.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path from 'node:path' 3 | import { fileURLToPath } from 'node:url' 4 | import { createRequire } from 'node:module' 5 | import { spawn } from 'node:child_process' 6 | 7 | const pkg = createRequire(import.meta.url)('../package.json') 8 | const __dirname = path.dirname(fileURLToPath(import.meta.url)) 9 | 10 | // write .debug.env 11 | const envContent = Object.entries(pkg.debug.env).map(([key, val]) => `${key}=${val}`) 12 | fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n')) 13 | 14 | // bootstrap 15 | spawn( 16 | // TODO: terminate `npm run dev` when Debug exits. 17 | process.platform === 'win32' ? 'npm.cmd' : 'npm', 18 | ['run', 'dev'], 19 | { 20 | stdio: 'inherit', 21 | env: Object.assign(process.env, { VSCODE_DEBUG: 'true' }), 22 | }, 23 | ) -------------------------------------------------------------------------------- /electron-react/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "mrmlnc.vscode-json5" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /electron-react/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "compounds": [ 7 | { 8 | "name": "Debug App", 9 | "preLaunchTask": "Before Debug", 10 | "configurations": [ 11 | "Debug Main Process", 12 | "Debug Renderer Process" 13 | ], 14 | "presentation": { 15 | "hidden": false, 16 | "group": "", 17 | "order": 1 18 | }, 19 | "stopAll": true 20 | } 21 | ], 22 | "configurations": [ 23 | { 24 | "name": "Debug Main Process", 25 | "type": "node", 26 | "request": "launch", 27 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron", 28 | "windows": { 29 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" 30 | }, 31 | "runtimeArgs": [ 32 | "--no-sandbox", 33 | "--remote-debugging-port=9229", 34 | "." 35 | ], 36 | "envFile": "${workspaceFolder}/.vscode/.debug.env", 37 | "console": "integratedTerminal" 38 | }, 39 | { 40 | "name": "Debug Renderer Process", 41 | "port": 9229, 42 | "request": "attach", 43 | "type": "chrome", 44 | "timeout": 60000, 45 | "skipFiles": [ 46 | "/**", 47 | "${workspaceRoot}/node_modules/**", 48 | "${workspaceRoot}/dist-electron/**", 49 | // Skip files in host(VITE_DEV_SERVER_URL) 50 | "http://127.0.0.1:7777/**" 51 | ] 52 | }, 53 | ] 54 | } -------------------------------------------------------------------------------- /electron-react/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "typescript.tsc.autoDetect": "off", 4 | "json.schemas": [ 5 | { 6 | "fileMatch": [ 7 | "/*electron-builder.json5", 8 | "/*electron-builder.json" 9 | ], 10 | "url": "https://json.schemastore.org/electron-builder" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /electron-react/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Before Debug", 8 | "type": "shell", 9 | "command": "node .vscode/.debug.script.mjs", 10 | "isBackground": true, 11 | "problemMatcher": { 12 | "owner": "typescript", 13 | "fileLocation": "relative", 14 | "pattern": { 15 | // TODO: correct "regexp" 16 | "regexp": "^([a-zA-Z]\\:\/?([\\w\\-]\/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$", 17 | "file": 1, 18 | "line": 3, 19 | "column": 4, 20 | "code": 5, 21 | "message": 6 22 | }, 23 | "background": { 24 | "activeOnStart": true, 25 | "beginsPattern": "^.*VITE v.* ready in \\d* ms.*$", 26 | "endsPattern": "^.*\\[startup\\] Electron App.*$" 27 | } 28 | } 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /electron-react/athena-website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /electron-react/athena-website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | navigate to electron-react/athena-website and run: 13 | ``` 14 | npm start 15 | ``` 16 | ``` 17 | $ yarn start 18 | ``` 19 | 20 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 21 | 22 | ### Build 23 | 24 | ``` 25 | $ yarn build 26 | ``` 27 | 28 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 29 | 30 | ### Deployment 31 | 32 | Using SSH: 33 | 34 | ``` 35 | $ USE_SSH=true yarn deploy 36 | ``` 37 | 38 | Not using SSH: 39 | 40 | ``` 41 | $ GIT_USER= yarn deploy 42 | ``` 43 | 44 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 45 | -------------------------------------------------------------------------------- /electron-react/athena-website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /electron-react/athena-website/blog/2019-05-28-first-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: first-blog-post 3 | title: First Blog Post 4 | authors: 5 | name: Gao Wei 6 | title: Docusaurus Core Team 7 | url: https://github.com/wgao19 8 | image_url: https://github.com/wgao19.png 9 | tags: [hola, docusaurus] 10 | --- 11 | 12 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 13 | -------------------------------------------------------------------------------- /electron-react/athena-website/blog/2019-05-29-long-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: long-blog-post 3 | title: Long Blog Post 4 | authors: endi 5 | tags: [hello, docusaurus] 6 | --- 7 | 8 | This is the summary of a very long blog post, 9 | 10 | Use a `` comment to limit blog post size in the list view. 11 | 12 | 13 | 14 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 15 | 16 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 17 | 18 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 19 | 20 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 21 | 22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 23 | 24 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 25 | 26 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 27 | 28 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 29 | 30 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 31 | 32 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 33 | 34 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 35 | 36 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 37 | 38 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 39 | 40 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 41 | 42 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 43 | 44 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 45 | -------------------------------------------------------------------------------- /electron-react/athena-website/blog/2021-08-01-mdx-blog-post.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: mdx-blog-post 3 | title: MDX Blog Post 4 | authors: [slorber] 5 | tags: [docusaurus] 6 | --- 7 | 8 | Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). 9 | 10 | :::tip 11 | 12 | Use the power of React to create interactive blog posts. 13 | 14 | ```js 15 | 16 | ``` 17 | 18 | 19 | 20 | ::: 21 | -------------------------------------------------------------------------------- /electron-react/athena-website/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg -------------------------------------------------------------------------------- /electron-react/athena-website/blog/2021-08-26-welcome/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: welcome 3 | title: Welcome 4 | authors: [slorber, yangshun] 5 | tags: [facebook, hello, docusaurus] 6 | --- 7 | 8 | [Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). 9 | 10 | Simply add Markdown files (or folders) to the `blog` directory. 11 | 12 | Regular blog authors can be added to `authors.yml`. 13 | 14 | The blog post date can be extracted from filenames, such as: 15 | 16 | - `2019-05-30-welcome.md` 17 | - `2019-05-30-welcome/index.md` 18 | 19 | A blog post folder can be convenient to co-locate blog post images: 20 | 21 | ![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) 22 | 23 | The blog supports tags as well! 24 | 25 | **And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. 26 | -------------------------------------------------------------------------------- /electron-react/athena-website/blog/authors.yml: -------------------------------------------------------------------------------- 1 | endi: 2 | name: Endilie Yacop Sucipto 3 | title: Maintainer of Docusaurus 4 | url: https://github.com/endiliey 5 | image_url: https://github.com/endiliey.png 6 | 7 | yangshun: 8 | name: Yangshun Tay 9 | title: Front End Engineer @ Facebook 10 | url: https://github.com/yangshun 11 | image_url: https://github.com/yangshun.png 12 | 13 | slorber: 14 | name: Sébastien Lorber 15 | title: Docusaurus maintainer 16 | url: https://sebastienlorber.com 17 | image_url: https://github.com/slorber.png 18 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/UI-mode/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "UI Mode", 3 | "position": 3, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/UI-mode/img/docsVersionDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/docs/UI-mode/img/docsVersionDropdown.png -------------------------------------------------------------------------------- /electron-react/athena-website/docs/UI-mode/img/localeDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/docs/UI-mode/img/localeDropdown.png -------------------------------------------------------------------------------- /electron-react/athena-website/docs/UI-mode/manage-docs-versions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/editing-your-component/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Editing Your Component", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Core AthenaJS Concepts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/editing-your-component/defining-actions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Mocking Functions 6 | 7 | In AthenaJS, the function terminal window is a powerful tool that allows users to import and define functions from component files to test and render components. Here's a step-by-step guide on how to use the function terminal window: 8 | 9 | - **Access the function terminal window**: Locate the function terminal window in the bottom-middle of the AthenaJS UI. This window is dedicated to creating and managing functions for your isolated component. 10 | 11 | - **Load the component file**: Use the "Load File" button to load your component file into AthenaJS. The component file will be parsed, and all of the functions defined in the file will be loaded into the function terminal window. 12 | 13 | - **Define functions in the function terminal window**: In the function terminal window, you can define functions or modify the existing ones that have been loaded from the component file. For example, you can define a function named `handleClick` that changes the state of the component when called. The syntax for defining a function in the function terminal window is the same as in a regular JavaScript file. 14 | 15 | - **Utilize the functions in the component**: Once the functions have been defined or imported in the function terminal window, they can be utilized in the component. You can call the functions in the JSX terminal window, passing in any necessary parameters. 16 | 17 | - **Preview the component**: The view component button will render a preview of the component in AthenaJS's component rendering panel. This allows you to see how the component behaves with specific function calls and make any necessary adjustments on the fly thanks to AthenaJS's live component rendering. 18 | 19 | - **Modify or remove functions**: If needed, you can easily modify or remove existing functions by accessing the function terminal window and editing or deleting the corresponding JavaScript entries. 20 | 21 | By following these steps, users can import and define functions from component files or external sources and utilize them in their AthenaJS components. -------------------------------------------------------------------------------- /electron-react/athena-website/docs/editing-your-component/mocking-props.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 0 3 | --- 4 | 5 | # Mocking Props 6 | 7 | In AthenaJS, mocking props is an essential aspect of component development and testing. It enables developers to simulate the data that their components receive from parent components or external sources, ensuring that they function correctly in various scenarios. Here is a step-by-step guide on how to write and use dummy props in AthenaJS: 8 | 9 | - **Access the props editor**: Find the props editor panel located in the bottom-left of the AthenaJS UI. This panel allows for the creation and management of prop mocks for your isolated component. 10 | 11 | - **Write the mock prop**: In the "Props" text area, you can load props from your component page and edit/create more mock props using JSON notation. For example, you can enter `{“count” : 1}` to create a dummy prop called "count" with a value of 1. 12 | 13 | - - For more complex prop values, you can use JSON objects or arrays, such as `{“items”: [{“id”:1, “name”: “Item 1”}, {“id”: 2, “name”: “Item 2”}]}`. 14 | 15 | - **Utilize the built-in linter**: While writing mock props, AthenaJS's built-in linter will check for syntax errors or issues in your JSON notation. If any problems are detected, the linter will notify you on the left side of the panel and provide helpful feedback if you hover over the notification. 16 | 17 | - **Preview the component**: The component will automatically update as you edit mock props in the editor. With the mock props defined, you can preview the component in AthenaJS's component rendering panel. This enables you to see how the component behaves with specific prop values and make necessary adjustments on the fly thanks to AthenaJS's live component rendering. 18 | 19 | - **Modify or remove mock props**: You can easily modify or remove existing mock props by accessing the Props panel and editing or deleting the corresponding JSON entries. 20 | 21 | By following these steps, you can efficiently create and manage mock props for your components in AthenaJS. 22 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/editing-your-component/mocking-state.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Mocking State 6 | 7 | AthenaJS offers a functional component syntax that allows users to simulate state, enabling developers to test their components' behavior in various scenarios. If you're looking to write and implement mock state using AthenaJS, here's a step-by-step guide: 8 | 9 | - **Load Hooks**: Head over to the AthenaJS application and open your project directory. Select the component file you want to modify, and its hooks will be loaded into the state terminal situated in the bottom-left corner of the homepage. 10 | 11 | - **Define State Variables**: Use the state window to define/edit the state variables you want to mock. 12 | 13 | - **Manipulate State in JSX**: In the JSX terminal located in the bottom-right corner of the UI, you can implement the state variables you have defined. 14 | 15 | By following these steps, you can easily create and use mock state in your AthenaJS project to test your components' functionality. -------------------------------------------------------------------------------- /electron-react/athena-website/docs/editing-your-component/rendering-component.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Rendering Your Component 6 | 7 | After defining the state, props, function definitions, and JSX, users can render their component in the Component window by following these steps: 8 | 9 | - **Update View**: To view the most recent changes made, click the 'Update View' button. This will trigger a re-render of the component. 10 | 11 | - **Save Component**: Users can save their components to their component library by giving them a name and clicking the 'Save Component' button. This will allow the component to be reused in UI mode. 12 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Getting Started 6 | 7 | ## Introduction to AthenaJS: 8 | 9 | AthenaJS is an Electron-based application that streamlines the development process of React components. Its key feature is the ability to **develop individual components in isolation**, allowing for rapid prototyping, testing, and iteration. By providing a dedicated environment for component creation, AthenaJS enhances efficiency and promotes best practices in React development. 10 | 11 | ### Key Features of AthenaJS Include: 12 | 13 | - **Intuitive interface** for editing components, mocking props, and managing state. This includes a built-in linter for JavaScript, JSON, and JSX. 14 | 15 | - Support for **defining custom actions** to manage component behavior and interactions. 16 | 17 | - **Live component rendering and previewing**, making it easy to visualize and test components on the fly. 18 | 19 | - **Render time calculations**, allowing developers to analyze component performance and optimize if needed. 20 | 21 | - **Export** functionality to integrate updated components seamlessly into your React application. 22 | 23 | - Ability to **edit React server components in isolation**, allowing developers to optimize performance and reduce the need for client-side rendering, further enhancing the React development experience. 24 | 25 | 26 | ## Prerequisities 27 | 28 | To get started with AthenaJS, it's important to ensure that your system meets the following requirements: 29 | 30 | 31 | - **Compatible operating system**: AthenaJS is available for Windows, macOS, and Linux. 32 | - **Basic knowledge of React**: Familiarity with React, its core concepts, and component development is highly recommended to use AthenaJS effectively. 33 | 34 | 35 | Once you have met these prerequisites, you can install AthenaJS and begin developing React components with enhanced performance insights and efficient workflows. 36 | 37 | ## Installing Athena JS 38 | 39 | Users will be able to download Athena JS either through our [homepage](http://localhost:3000/) or our [Github](https://github.com/oslabs-beta/Athena). 40 | 41 | **Github Instructions:** 42 | 43 | First, navigate to the Github repository URL and fork the repository. 44 | 45 | Next, clone the repository to your local machine. 46 | 47 | ```bash 48 | git clone https://github.com/YOUR_USERNAME_HERE/Athena.git 49 | ``` 50 | 51 | Navigate into the newly created Athena Folder, install all necessary dependencies, and spin up the app 52 | 53 | ```bash 54 | cd Athena 55 | npm install 56 | npm run dev 57 | ``` 58 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tutorial - Basics", 3 | "position": 4, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "Core AthenaJS Concepts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/congratulations.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Defining Actions 6 | 7 | You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. 8 | 9 | Docusaurus has **much more to offer**! 10 | 11 | Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. 12 | 13 | Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) 14 | 15 | ## What's next? 16 | 17 | - Read the [official documentation](https://docusaurus.io/) 18 | - Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config) 19 | - Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration) 20 | - Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) 21 | - Add a [search bar](https://docusaurus.io/docs/search) 22 | - Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) 23 | - Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) 24 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/create-a-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Mocking Props 6 | 7 | Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... 8 | 9 | ## Create your first Post 10 | 11 | Create a file at `blog/2021-02-28-greetings.md`: 12 | 13 | ```md title="blog/2021-02-28-greetings.md" 14 | --- 15 | slug: greetings 16 | title: Greetings! 17 | authors: 18 | - name: Joel Marcey 19 | title: Co-creator of Docusaurus 1 20 | url: https://github.com/JoelMarcey 21 | image_url: https://github.com/JoelMarcey.png 22 | - name: Sébastien Lorber 23 | title: Docusaurus maintainer 24 | url: https://sebastienlorber.com 25 | image_url: https://github.com/slorber.png 26 | tags: [greetings] 27 | --- 28 | 29 | Congratulations, you have made your first post! 30 | 31 | Feel free to play around and edit this post as much you like. 32 | ``` 33 | 34 | A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings). 35 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/create-a-document.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Editing Your Component 6 | 7 | Documents are **groups of pages** connected through: 8 | 9 | - a **sidebar** 10 | - **previous/next navigation** 11 | - **versioning** 12 | 13 | ## Create your first Doc 14 | 15 | Create a Markdown file at `docs/hello.md`: 16 | 17 | ```md title="docs/hello.md" 18 | # Hello 19 | 20 | This is my **first Docusaurus document**! 21 | ``` 22 | 23 | A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello). 24 | 25 | ## Configure the Sidebar 26 | 27 | Docusaurus automatically **creates a sidebar** from the `docs` folder. 28 | 29 | Add metadata to customize the sidebar label and position: 30 | 31 | ```md title="docs/hello.md" {1-4} 32 | --- 33 | sidebar_label: 'Hi!' 34 | sidebar_position: 3 35 | --- 36 | 37 | # Hello 38 | 39 | This is my **first Docusaurus document**! 40 | ``` 41 | 42 | It is also possible to create your sidebar explicitly in `sidebars.js`: 43 | 44 | ```js title="sidebars.js" 45 | module.exports = { 46 | tutorialSidebar: [ 47 | 'intro', 48 | // highlight-next-line 49 | 'hello', 50 | { 51 | type: 'category', 52 | label: 'Tutorial', 53 | items: ['tutorial-basics/create-a-document'], 54 | }, 55 | ], 56 | }; 57 | ``` 58 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/create-a-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Importing Your File 6 | 7 | Add **Markdown or React** files to `src/pages` to create a **standalone page**: 8 | 9 | - `src/pages/index.js` → `localhost:3000/` 10 | - `src/pages/foo.md` → `localhost:3000/foo` 11 | - `src/pages/foo/bar.js` → `localhost:3000/foo/bar` 12 | 13 | ## Create your first React Page 14 | 15 | Create a file at `src/pages/my-react-page.js`: 16 | 17 | ```jsx title="src/pages/my-react-page.js" 18 | import React from 'react'; 19 | import Layout from '@theme/Layout'; 20 | 21 | export default function MyReactPage() { 22 | return ( 23 | 24 |

My React page

25 |

This is a React page

26 |
27 | ); 28 | } 29 | ``` 30 | 31 | A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). 32 | 33 | ## Create your first Markdown Page 34 | 35 | Create a file at `src/pages/my-markdown-page.md`: 36 | 37 | ```mdx title="src/pages/my-markdown-page.md" 38 | # My Markdown page 39 | 40 | This is a Markdown page 41 | ``` 42 | 43 | A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). 44 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/deploy-your-site.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Mocking State 6 | 7 | Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). 8 | 9 | It builds your site as simple **static HTML, JavaScript and CSS files**. 10 | 11 | ## Build your site 12 | 13 | Build your site **for production**: 14 | 15 | ```bash 16 | npm run build 17 | ``` 18 | 19 | The static files are generated in the `build` folder. 20 | 21 | ## Deploy your site 22 | 23 | Test your production build locally: 24 | 25 | ```bash 26 | npm run serve 27 | ``` 28 | 29 | The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). 30 | 31 | You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). 32 | -------------------------------------------------------------------------------- /electron-react/athena-website/docs/tutorial-basics/markdown-features.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # Markdown Features 6 | 7 | Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. 8 | 9 | ## Front Matter 10 | 11 | Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): 12 | 13 | ```text title="my-doc.md" 14 | // highlight-start 15 | --- 16 | id: my-doc-id 17 | title: My document title 18 | description: My document description 19 | slug: /my-custom-url 20 | --- 21 | // highlight-end 22 | 23 | ## Markdown heading 24 | 25 | Markdown text with [links](./hello.md) 26 | ``` 27 | 28 | ## Links 29 | 30 | Regular Markdown links are supported, using url paths or relative file paths. 31 | 32 | ```md 33 | Let's see how to [Create a page](/create-a-page). 34 | ``` 35 | 36 | ```md 37 | Let's see how to [Create a page](./create-a-page.md). 38 | ``` 39 | 40 | **Result:** Let's see how to [Create a page](./create-a-page.md). 41 | 42 | ## Images 43 | 44 | Regular Markdown images are supported. 45 | 46 | You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`): 47 | 48 | ```md 49 | ![Docusaurus logo](/img/docusaurus.png) 50 | ``` 51 | 52 | ![Docusaurus logo](/img/docusaurus.png) 53 | 54 | You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them: 55 | 56 | ```md 57 | ![Docusaurus logo](./img/docusaurus.png) 58 | ``` 59 | 60 | ## Code Blocks 61 | 62 | Markdown code blocks are supported with Syntax highlighting. 63 | 64 | ```jsx title="src/components/HelloDocusaurus.js" 65 | function HelloDocusaurus() { 66 | return ( 67 |

Hello, Docusaurus!

68 | ) 69 | } 70 | ``` 71 | 72 | ```jsx title="src/components/HelloDocusaurus.js" 73 | function HelloDocusaurus() { 74 | return

Hello, Docusaurus!

; 75 | } 76 | ``` 77 | 78 | ## Admonitions 79 | 80 | Docusaurus has a special syntax to create admonitions and callouts: 81 | 82 | :::tip My tip 83 | 84 | Use this awesome feature option 85 | 86 | ::: 87 | 88 | :::danger Take care 89 | 90 | This action is dangerous 91 | 92 | ::: 93 | 94 | :::tip My tip 95 | 96 | Use this awesome feature option 97 | 98 | ::: 99 | 100 | :::danger Take care 101 | 102 | This action is dangerous 103 | 104 | ::: 105 | 106 | ## MDX and React Components 107 | 108 | [MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: 109 | 110 | ```jsx 111 | export const Highlight = ({children, color}) => ( 112 | { 121 | alert(`You clicked the color ${color} with label ${children}`) 122 | }}> 123 | {children} 124 | 125 | ); 126 | 127 | This is Docusaurus green ! 128 | 129 | This is Facebook blue ! 130 | ``` 131 | 132 | export const Highlight = ({children, color}) => ( 133 | { 142 | alert(`You clicked the color ${color} with label ${children}`); 143 | }}> 144 | {children} 145 | 146 | ); 147 | 148 | This is Docusaurus green ! 149 | 150 | This is Facebook blue ! 151 | -------------------------------------------------------------------------------- /electron-react/athena-website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Note: type annotations allow type checking and IDEs autocompletion 3 | 4 | const lightCodeTheme = require('prism-react-renderer/themes/github'); 5 | const darkCodeTheme = require('prism-react-renderer/themes/dracula'); 6 | 7 | /** @type {import('@docusaurus/types').Config} */ 8 | const config = { 9 | title: 'AthenaJS', 10 | tagline: 'Building Components Has Never Been This Easy', 11 | favicon: 'img/favicon.ico', 12 | 13 | // Set the production url of your site here 14 | url: 'https://your-docusaurus-test-site.com', 15 | // Set the // pathname under which your site is served 16 | // For GitHub pages deployment, it is often '//' 17 | baseUrl: '/', 18 | 19 | // GitHub pages deployment config. 20 | // If you aren't using GitHub pages, you don't need these. 21 | organizationName: 'OSLABS', // Usually your GitHub org/user name. 22 | projectName: 'Athena', // Usually your repo name. 23 | 24 | onBrokenLinks: 'throw', 25 | onBrokenMarkdownLinks: 'warn', 26 | 27 | // Even if you don't use internalization, you can use this field to set useful 28 | // metadata like html lang. For example, if your site is Chinese, you may want 29 | // to replace "en" with "zh-Hans". 30 | i18n: { 31 | defaultLocale: 'en', 32 | locales: ['en'], 33 | }, 34 | 35 | presets: [ 36 | [ 37 | 'classic', 38 | /** @type {import('@docusaurus/preset-classic').Options} */ 39 | ({ 40 | docs: { 41 | sidebarPath: require.resolve('./sidebars.js'), 42 | // Please change this to your repo. 43 | // Remove this to remove the "edit this page" links. 44 | editUrl: 45 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', 46 | }, 47 | blog: { 48 | showReadingTime: true, 49 | // Please change this to your repo. 50 | // Remove this to remove the "edit this page" links. 51 | editUrl: 52 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', 53 | }, 54 | theme: { 55 | customCss: require.resolve('./src/css/custom.css'), 56 | }, 57 | }), 58 | ], 59 | ], 60 | 61 | themeConfig: 62 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 63 | ({ 64 | // Replace with your project's social card 65 | image: 'img/athenajs_social_card.png', 66 | navbar: { 67 | logo: { 68 | alt: 'Athena Logo', 69 | src: 'img/navbar_logo_light.png', 70 | srcDark: 'img/navbar_logo_dark.png', 71 | }, 72 | items: [ 73 | { 74 | type: 'docSidebar', 75 | sidebarId: 'tutorialSidebar', 76 | position: 'left', 77 | label: 'Tutorial', 78 | }, 79 | {to: '/blog', label: 'Blog', position: 'left'}, 80 | { 81 | href: 'https://github.com/oslabs-beta/Athena', 82 | label: 'GitHub', 83 | position: 'right', 84 | }, 85 | ], 86 | }, 87 | footer: { 88 | style: 'dark', 89 | links: [ 90 | { 91 | title: 'Docs', 92 | items: [ 93 | { 94 | label: 'Tutorial', 95 | to: '/docs/intro', 96 | }, 97 | ], 98 | }, 99 | { 100 | title: 'Community', 101 | items: [ 102 | { 103 | label: 'Stack Overflow', 104 | href: 'https://stackoverflow.com/questions/tagged/docusaurus', 105 | }, 106 | { 107 | label: 'Discord', 108 | href: 'https://discordapp.com/invite/docusaurus', 109 | }, 110 | { 111 | label: 'Twitter', 112 | href: 'https://twitter.com/docusaurus', 113 | }, 114 | ], 115 | }, 116 | { 117 | title: 'More', 118 | items: [ 119 | { 120 | label: 'Blog', 121 | to: '/blog', 122 | }, 123 | { 124 | label: 'GitHub', 125 | href: 'https://github.com/oslabs-beta/Athena', 126 | }, 127 | ], 128 | }, 129 | ], 130 | copyright: `Copyright © ${new Date().getFullYear()} Wheisker Co. Inc.`, 131 | }, 132 | prism: { 133 | theme: lightCodeTheme, 134 | darkTheme: darkCodeTheme, 135 | }, 136 | }), 137 | }; 138 | 139 | module.exports = config; 140 | -------------------------------------------------------------------------------- /electron-react/athena-website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "athena-website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "2.4.0", 18 | "@docusaurus/preset-classic": "2.4.0", 19 | "@mdx-js/react": "^1.6.22", 20 | "clsx": "^1.2.1", 21 | "prism-react-renderer": "^1.3.5", 22 | "react": "^17.0.2", 23 | "react-dom": "^17.0.2" 24 | }, 25 | "devDependencies": { 26 | "@docusaurus/module-type-aliases": "^2.4.0", 27 | "@tsconfig/docusaurus": "^1.0.7", 28 | "typescript": "^5.0.2" 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.5%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | }, 42 | "engines": { 43 | "node": ">=16.14" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /electron-react/athena-website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | module.exports = sidebars; 34 | -------------------------------------------------------------------------------- /electron-react/athena-website/src/components/HomepageFeatures/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import styles from './styles.module.css'; 4 | 5 | const FeatureList = [ 6 | { 7 | title: 'Edit/Develop Components With Live Rendering', 8 | img: '../../static/img/athenaFull_transparent.jpg', 9 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, 10 | description: ( 11 | <> 12 | AthenaJS lets users to either edit currently existing components from your 13 | project or develop new components for use in your project. 14 | 15 | ), 16 | }, 17 | { 18 | title: 'Build UI Screenshots from Saved Component Library', 19 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, 20 | description: ( 21 | <> 22 | AthenaJS allows users to save their newly edited/created components to a component library 23 | which can then be used to create mock UI images from their saved components. 24 | 25 | ), 26 | }, 27 | { 28 | title: 'Easily Export Created/Updated Components back to Project', 29 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, 30 | description: ( 31 | <> 32 | 33 | 34 | Extend or customize your website layout by reusing React. Docusaurus can 35 | be extended while reusing the same header and footer. 36 | 37 | ), 38 | }, 39 | ]; 40 | 41 | function Feature({Svg, title, description}) { 42 | return ( 43 |
44 |
45 | {/* */} 46 |
47 |
48 |

{title}

49 |

{description}

50 |
51 |
52 | ); 53 | } 54 | 55 | export default function HomepageFeatures() { 56 | return ( 57 |
58 |
59 |
60 | {FeatureList.map((props, idx) => ( 61 | 62 | ))} 63 |
64 |
65 |
66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /electron-react/athena-website/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /electron-react/athena-website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #663eFF; 10 | --ifm-color-primary-dark: #7c5CFF; 11 | --ifm-color-primary-darker: #4B1FFF; 12 | --ifm-color-primary-darkest: #3100f5; 13 | --ifm-color-primary-light: #8D70FF; 14 | --ifm-color-primary-lighter: #AD99FF; 15 | --ifm-color-primary-lightest: #CeC2FF; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | :root strong { 21 | color: #663eFF; 22 | } 23 | 24 | /* :root a { 25 | color: rgb(255,240,69); 26 | } */ 27 | 28 | 29 | 30 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 31 | [data-theme='dark'] { 32 | --ifm-color-primary: #663eFF; 33 | --ifm-color-primary-dark: #7c5CFF; 34 | --ifm-color-primary-darker: #4B1FFF; 35 | --ifm-color-primary-darkest: #3100f5; 36 | --ifm-color-primary-light: #8D70FF; 37 | --ifm-color-primary-lighter: #AD99FF; 38 | --ifm-color-primary-lightest: #CeC2FF; 39 | --ifm-code-font-size: 95%; 40 | --docusaurus-highlighted-code-line-bg: rgba(255, 240, 69, 0.336); 41 | --strong: rgb(255, 240, 69); 42 | } 43 | 44 | [data-theme='dark'] strong { 45 | color:rgb(255,240,69); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /electron-react/athena-website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import Link from '@docusaurus/Link'; 4 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 5 | import Layout from '@theme/Layout'; 6 | import HomepageFeatures from '@site/src/components/HomepageFeatures'; 7 | 8 | import styles from './index.module.css'; 9 | 10 | function HomepageHeader() { 11 | const {siteConfig} = useDocusaurusContext(); 12 | return ( 13 |
14 |
15 |

{siteConfig.title}

16 |

{siteConfig.tagline}

17 |
18 | 21 | Download 22 | 23 | 26 | Getting Started 27 | 28 |
29 |
30 |
31 | ); 32 | } 33 | 34 | export default function Home() { 35 | const {siteConfig} = useDocusaurusContext(); 36 | return ( 37 | 40 | 41 |
42 | 43 |
44 |
45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /electron-react/athena-website/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 996px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | flex-direction:column; 24 | } 25 | 26 | .margin{ 27 | margin: 10px; 28 | } 29 | -------------------------------------------------------------------------------- /electron-react/athena-website/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /electron-react/athena-website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/.nojekyll -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/athenaFull_transparent.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/athenaFull_transparent.jpg -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/athena_icon_whitebg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/athena_icon_whitebg.png -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/athenajs-social-card.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/athenajs-social-card.psd -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/athenajs_social_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/athenajs_social_card.png -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/docusaurus.png -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/favicon.ico -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/navbar_logo_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/navbar_logo_dark.png -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/navbar_logo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/athena-website/static/img/navbar_logo_light.png -------------------------------------------------------------------------------- /electron-react/athena-website/static/img/undraw_docusaurus_tree.svg: -------------------------------------------------------------------------------- 1 | 2 | Focus on What Matters 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /electron-react/athena-website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/docusaurus/tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | } 6 | } -------------------------------------------------------------------------------- /electron-react/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', {targets: {node: 'current'}}], 4 | '@babel/preset-typescript', 5 | ], 6 | }; -------------------------------------------------------------------------------- /electron-react/build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/build/icon.icns -------------------------------------------------------------------------------- /electron-react/build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/build/icon.png -------------------------------------------------------------------------------- /electron-react/electron-builder.json5: -------------------------------------------------------------------------------- 1 | /* 2 | * @see https://www.electron.build/configuration/configuration 3 | */ 4 | { 5 | "appId": "Athena", 6 | "asar": true, 7 | "directories": { 8 | "output": "release/${version}" 9 | }, 10 | "files": [ 11 | "dist-electron", 12 | "dist", 13 | "src/assets/**/*" 14 | ], 15 | "mac": { 16 | "artifactName": "${productName}_${version}.${ext}", 17 | "icon": "build/icon.png", 18 | "target": [ 19 | "dmg", 20 | "zip" 21 | ] 22 | }, 23 | "win": { 24 | "target": [ 25 | { 26 | "target": "nsis", 27 | "arch": [ 28 | "x64" 29 | ] 30 | } 31 | ], 32 | "artifactName": "${productName}_${version}.${ext}", 33 | "icon": "build/icon.png" 34 | }, 35 | "nsis": { 36 | "oneClick": false, 37 | "perMachine": false, 38 | "allowToChangeInstallationDirectory": true, 39 | "deleteAppDataOnUninstall": false 40 | }, 41 | "publish": { 42 | "provider": "generic", 43 | "channel": "latest", 44 | "url": "Athena_URL" 45 | } 46 | } -------------------------------------------------------------------------------- /electron-react/electron/electron-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare namespace NodeJS { 4 | interface ProcessEnv { 5 | VSCODE_DEBUG?: 'true' 6 | DIST_ELECTRON: string 7 | DIST: string 8 | /** /dist/ or /public/ */ 9 | PUBLIC: string 10 | } 11 | } -------------------------------------------------------------------------------- /electron-react/electron/main/index.ts: -------------------------------------------------------------------------------- 1 | import { app, BrowserWindow, shell, ipcMain, WebPreferences, dialog } from 'electron' 2 | import { release } from 'node:os' 3 | import { join } from 'node:path' 4 | import { update } from './update' 5 | import { readdirSync } from 'fs' 6 | import path from 'path' 7 | const fs = require('fs'); 8 | 9 | // The built directory structure 10 | // 11 | // ├─┬ dist-electron 12 | // │ ├─┬ main 13 | // │ │ └── index.js > Electron-Main 14 | // │ └─┬ preload 15 | // │ └── index.js > Preload-Scripts 16 | // ├─┬ dist 17 | // │ └── index.html > Electron-Renderer 18 | // 19 | process.env.DIST_ELECTRON = join(__dirname, '../') 20 | process.env.DIST = join(process.env.DIST_ELECTRON, '../dist') 21 | process.env.PUBLIC = process.env.VITE_DEV_SERVER_URL 22 | ? join(process.env.DIST_ELECTRON, '../public') 23 | : process.env.DIST 24 | 25 | // Disable GPU Acceleration for Windows 7 26 | if (release().startsWith('6.1')) app.disableHardwareAcceleration() 27 | 28 | // Set application name for Windows 10+ notifications 29 | if (process.platform === 'win32') app.setAppUserModelId(app.getName()) 30 | 31 | if (!app.requestSingleInstanceLock()) { 32 | app.quit() 33 | process.exit(0) 34 | } 35 | 36 | // Remove electron security warnings 37 | // This warning only shows in development mode 38 | // Read more on https://www.electronjs.org/docs/latest/tutorial/security 39 | // process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true' 40 | 41 | let win: BrowserWindow | null = null 42 | // Here, you can also use other preload 43 | const preload = join(__dirname, '../preload/index.js') 44 | const url = process.env.VITE_DEV_SERVER_URL 45 | const indexHtml = join(process.env.DIST, 'index.html') 46 | require('@electron/remote/main').initialize(); 47 | 48 | async function createWindow() { 49 | win = new BrowserWindow({ 50 | title: 'Main window', 51 | width: 1600, 52 | height: 1000, 53 | minWidth: 850, 54 | minHeight: 860, 55 | webPreferences: { 56 | preload, 57 | // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production 58 | // Consider using contextBridge.exposeInMainWorld 59 | // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation 60 | nodeIntegration: true, 61 | contextIsolation: false, 62 | } 63 | }) 64 | 65 | if (process.env.VITE_DEV_SERVER_URL) { // electron-vite-vue#298 66 | win.loadURL(url) 67 | // Open devTool if the app is not packaged 68 | win.webContents.openDevTools() 69 | } else { 70 | win.loadFile(indexHtml) 71 | } 72 | 73 | // Test actively push message to the Electron-Renderer 74 | win.webContents.on('did-finish-load', () => { 75 | win?.webContents.send('main-process-message', new Date().toLocaleString()) 76 | }) 77 | 78 | // Make all links open with the browser, not with the application 79 | win.webContents.setWindowOpenHandler(({ url }) => { 80 | if (url.startsWith('https:')) shell.openExternal(url) 81 | return { action: 'deny' } 82 | }) 83 | 84 | // Apply electron-updater 85 | update(win) 86 | } 87 | 88 | app.whenReady().then(createWindow) 89 | 90 | app.on('browser-window-created', (_, window) => { 91 | require("@electron/remote/main").enable(window.webContents) 92 | }) 93 | 94 | app.on('window-all-closed', () => { 95 | win = null 96 | if (process.platform !== 'darwin') app.quit() 97 | }) 98 | 99 | app.on('second-instance', () => { 100 | if (win) { 101 | // Focus on the main window if the user tried to open another 102 | if (win.isMinimized()) win.restore() 103 | win.focus() 104 | } 105 | }) 106 | 107 | app.on('activate', () => { 108 | const allWindows = BrowserWindow.getAllWindows() 109 | if (allWindows.length) { 110 | allWindows[0].focus() 111 | } else { 112 | createWindow() 113 | } 114 | }) 115 | 116 | 117 | 118 | // New window example arg: new windows url 119 | ipcMain.handle('open-win', (_, arg) => { 120 | const childWindow = new BrowserWindow({ 121 | webPreferences: { 122 | preload, 123 | nodeIntegration: true, 124 | contextIsolation: false, 125 | } 126 | }) 127 | 128 | if (process.env.VITE_DEV_SERVER_URL) { 129 | childWindow.loadURL(`${url}#${arg}`) 130 | } else { 131 | childWindow.loadFile(indexHtml, { hash: arg }) 132 | } 133 | }) 134 | 135 | ipcMain.on('OpenFolder', (e) => { 136 | const dialogOptions = { 137 | properties: ['openDirectory'] 138 | } 139 | e.returnValue = dialog.showOpenDialogSync(dialogOptions); 140 | }) 141 | 142 | ipcMain.on('ReadDir', (e, projectFilePath) => { 143 | e.returnValue = readdirSync(projectFilePath) 144 | }) 145 | 146 | ipcMain.on('save-file-dialog', (event, fileContent) => { 147 | dialog.showSaveDialog({ 148 | filters: [ 149 | { name: 'JSX', extensions: ['jsx'] } 150 | ] 151 | }).then(result => { 152 | if (!result.canceled) { 153 | const filePath = result.filePath; 154 | 155 | fs.writeFile(filePath, fileContent, (err) => { 156 | if (err) { 157 | console.log(`Error saving file: ${err.message}`); 158 | event.reply('saved-file', null); 159 | } else { 160 | event.reply('saved-file', filePath); 161 | } 162 | }); 163 | } else { 164 | event.reply('saved-file', null); 165 | } 166 | }).catch(err => { 167 | console.log(`Error showing save dialog: ${err.message}`); 168 | event.reply('saved-file', null); 169 | }); 170 | }); 171 | 172 | -------------------------------------------------------------------------------- /electron-react/electron/main/update.ts: -------------------------------------------------------------------------------- 1 | import { app, ipcMain } from 'electron' 2 | import { 3 | type ProgressInfo, 4 | type UpdateDownloadedEvent, 5 | autoUpdater 6 | } from 'electron-updater' 7 | 8 | export function update(win: Electron.BrowserWindow) { 9 | 10 | // When set to false, the update download will be triggered through the API 11 | autoUpdater.autoDownload = false 12 | autoUpdater.disableWebInstaller = false 13 | autoUpdater.allowDowngrade = false 14 | 15 | // start check 16 | autoUpdater.on('checking-for-update', function () { }) 17 | // update available 18 | autoUpdater.on('update-available', (arg) => { 19 | win.webContents.send('update-can-available', { update: true, version: app.getVersion(), newVersion: arg?.version }) 20 | }) 21 | // update not available 22 | autoUpdater.on('update-not-available', (arg) => { 23 | win.webContents.send('update-can-available', { update: false, version: app.getVersion(), newVersion: arg?.version }) 24 | }) 25 | 26 | // Checking for updates 27 | ipcMain.handle('check-update', async () => { 28 | if (!app.isPackaged) { 29 | const error = new Error('The update feature is only available after the package.') 30 | return { message: error.message, error } 31 | } 32 | 33 | try { 34 | return await autoUpdater.checkForUpdatesAndNotify() 35 | } catch (error) { 36 | return { message: 'Network error', error } 37 | } 38 | }) 39 | 40 | // Start downloading and feedback on progress 41 | ipcMain.handle('start-download', (event) => { 42 | startDownload( 43 | (error, progressInfo) => { 44 | if (error) { 45 | // feedback download error message 46 | event.sender.send('update-error', { message: error.message, error }) 47 | } else { 48 | // feedback update progress message 49 | event.sender.send('download-progress', progressInfo) 50 | } 51 | }, 52 | () => { 53 | // feedback update downloaded message 54 | event.sender.send('update-downloaded') 55 | } 56 | ) 57 | }) 58 | 59 | // Install now 60 | ipcMain.handle('quit-and-install', () => { 61 | autoUpdater.quitAndInstall(false, true) 62 | }) 63 | } 64 | 65 | function startDownload( 66 | callback: (error: Error | null, info: ProgressInfo) => void, 67 | complete: (evnet: UpdateDownloadedEvent) => void, 68 | ) { 69 | autoUpdater.on('download-progress', info => callback(null, info)) 70 | autoUpdater.on('error', error => callback(error, null)) 71 | autoUpdater.on('update-downloaded', complete) 72 | autoUpdater.downloadUpdate() 73 | } 74 | -------------------------------------------------------------------------------- /electron-react/electron/preload/index.ts: -------------------------------------------------------------------------------- 1 | function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) { 2 | return new Promise(resolve => { 3 | if (condition.includes(document.readyState)) { 4 | resolve(true) 5 | } else { 6 | document.addEventListener('readystatechange', () => { 7 | if (condition.includes(document.readyState)) { 8 | resolve(true) 9 | } 10 | }) 11 | } 12 | }) 13 | } 14 | 15 | const safeDOM = { 16 | append(parent: HTMLElement, child: HTMLElement) { 17 | if (!Array.from(parent.children).find(e => e === child)) { 18 | return parent.appendChild(child) 19 | } 20 | }, 21 | remove(parent: HTMLElement, child: HTMLElement) { 22 | if (Array.from(parent.children).find(e => e === child)) { 23 | return parent.removeChild(child) 24 | } 25 | }, 26 | } 27 | 28 | /** 29 | * https://tobiasahlin.com/spinkit 30 | * https://connoratherton.com/loaders 31 | * https://projects.lukehaas.me/css-loaders 32 | * https://matejkustec.github.io/SpinThatShit 33 | */ 34 | function useLoading() { 35 | const className = `loaders-css__circular-spinner`; 36 | const styleContent = ` 37 | @keyframes circular-spinner { 38 | 0% { transform: rotate(0deg); } 39 | 100% { transform: rotate(360deg); } 40 | } 41 | 42 | .${className} { 43 | width: 50px; 44 | height: 50px; 45 | border-radius: 50%; 46 | border: 6px solid #A499BE; 47 | border-top-color: #663EFF; 48 | animation: circular-spinner 1s linear infinite; 49 | background-color: white; 50 | } 51 | 52 | .app-loading-wrap { 53 | position: fixed; 54 | top: 0; 55 | left: 0; 56 | width: 100%; 57 | height: 100%; 58 | display: flex; 59 | justify-content: center; 60 | align-items: center; 61 | z-index: 9999; 62 | background-color: rgba(255, 255, 255, 0.8); 63 | opacity: 0; 64 | animation: fade-in 0.5s ease-in-out forwards; 65 | } 66 | 67 | .app-loading-wrap img { 68 | display: block; 69 | margin: 0 auto 20px auto; 70 | max-width: 100%; 71 | height: auto; 72 | } 73 | 74 | .spinner-wrap { 75 | display: flex; 76 | justify-content: center; 77 | align-items: center; 78 | flex-direction: column; 79 | } 80 | 81 | @keyframes fade-in { 82 | from { opacity: 0; } 83 | to { opacity: 1; } 84 | } 85 | 86 | @keyframes fade-out { 87 | from { opacity: 1; } 88 | to { opacity: 0; } 89 | } 90 | `; 91 | 92 | const oStyle = document.createElement('style'); 93 | const oDiv = document.createElement('div'); 94 | 95 | oStyle.id = 'app-loading-style'; 96 | oStyle.innerHTML = styleContent; 97 | oDiv.className = 'app-loading-wrap'; 98 | oDiv.innerHTML = ` 99 |
100 | Loading... 101 |
102 |
103 | `; 104 | 105 | return { 106 | appendLoading() { 107 | safeDOM.append(document.head, oStyle); 108 | safeDOM.append(document.body, oDiv); 109 | }, 110 | removeLoading() { 111 | oDiv.addEventListener('animationend', () => { 112 | safeDOM.remove(document.head, oStyle); 113 | safeDOM.remove(document.body, oDiv); 114 | }); 115 | oDiv.style.animation = 'fade-out 0.5s ease-in-out forwards'; 116 | }, 117 | }; 118 | } 119 | 120 | // ---------------------------------------------------------------------- 121 | 122 | const { appendLoading, removeLoading } = useLoading() 123 | domReady().then(appendLoading) 124 | 125 | window.onmessage = (ev) => { 126 | ev.data.payload === 'removeLoading' && removeLoading() 127 | } 128 | 129 | setTimeout(removeLoading, 4999) -------------------------------------------------------------------------------- /electron-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Athena 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /electron-react/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'jest-environment-jsdom', 3 | verbose: true, 4 | // other Jest configuration options... 5 | }; -------------------------------------------------------------------------------- /electron-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "athena", 3 | "version": "1.0.0", 4 | "main": "dist-electron/main/index.js", 5 | "description": "Rapid development of React components in isolation", 6 | "license": "MIT", 7 | "private": true, 8 | "debug": { 9 | "env": { 10 | "VITE_DEV_SERVER_URL": "http://127.0.0.1:7777/" 11 | } 12 | }, 13 | "scripts": { 14 | "dev": "vite", 15 | "build": "tsc && vite build && electron-builder", 16 | "preview": "vite preview", 17 | "pree2e": "vite build --mode=test", 18 | "e2e": "playwright test", 19 | "test": "jest" 20 | }, 21 | "dependencies": { 22 | "@babel/parser": "^7.21.3", 23 | "@babel/traverse": "^7.21.3", 24 | "@electron/remote": "^2.0.9", 25 | "@reactflow/node-resizer": "^2.1.0", 26 | "@types/babel__traverse": "^7.18.3", 27 | "ace-builds": "^1.16.0", 28 | "babel-loader": "^9.1.2", 29 | "chart.js": "^4.2.1", 30 | "electron-updater": "^5.3.0", 31 | "fetch-mock": "^9.11.0", 32 | "framer-motion": "^10.9.1", 33 | "html2canvas": "^1.4.1", 34 | "i": "^0.3.7", 35 | "jest": "^29.5.0", 36 | "npm": "^9.6.2", 37 | "re-resizable": "^6.9.9", 38 | "react-ace": "^10.1.0", 39 | "react-chartjs-2": "^5.2.0", 40 | "react-icons": "^4.8.0", 41 | "react-jsx-parser": "^1.29.0", 42 | "reactflow": "^11.6.1", 43 | "stringify-object": "^5.0.0", 44 | "styled-components": "^5.3.9" 45 | }, 46 | "devDependencies": { 47 | "@babel/preset-env": "^7.21.4", 48 | "@babel/preset-react": "^7.18.6", 49 | "@babel/preset-typescript": "^7.21.4", 50 | "@playwright/test": "^1.31.0", 51 | "@testing-library/jest-dom": "^5.16.5", 52 | "@testing-library/react": "^14.0.0", 53 | "@testing-library/user-event": "^14.4.3", 54 | "@types/react": "^18.0.28", 55 | "@types/react-dom": "^18.0.11", 56 | "@types/styled-components": "^5.1.26", 57 | "@typescript-eslint/eslint-plugin": "^5.55.0", 58 | "@typescript-eslint/parser": "^5.55.0", 59 | "@vitejs/plugin-react": "^3.1.0", 60 | "electron": "^23.2.0", 61 | "electron-builder": "^23.6.0", 62 | "eslint": "^8.36.0", 63 | "eslint-plugin-react": "^7.32.2", 64 | "jest": "^29.5.0", 65 | "jest-environment-jsdom": "^29.5.0", 66 | "react": "^18.2.0", 67 | "react-dom": "^18.2.0", 68 | "react-live": "^3.1.2", 69 | "sass": "^1.58.3", 70 | "ts-jest": "^29.1.0", 71 | "typescript": "^4.9.5", 72 | "vite": "^4.1.4", 73 | "vite-electron-plugin": "^0.8.2", 74 | "vite-plugin-electron": "^0.11.1", 75 | "vite-plugin-electron-renderer": "^0.12.1" 76 | }, 77 | "babel": { 78 | "presets": [ 79 | "@babel/preset-env", 80 | "@babel/preset-react" 81 | ] 82 | }, 83 | "engines": { 84 | "node": "^14.18.0 || >=16.0.0" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /electron-react/playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from "@playwright/test"; 2 | 3 | /** 4 | * Read environment variables from file. 5 | * https://github.com/motdotla/dotenv 6 | */ 7 | // require('dotenv').config(); 8 | 9 | /** 10 | * See https://playwright.dev/docs/test-configuration. 11 | */ 12 | const config: PlaywrightTestConfig = { 13 | testDir: "./e2e", 14 | /* Maximum time one test can run for. */ 15 | timeout: 30 * 1000, 16 | expect: { 17 | /** 18 | * Maximum time expect() should wait for the condition to be met. 19 | * For example in `await expect(locator).toHaveText();` 20 | */ 21 | timeout: 5000, 22 | }, 23 | /* Run tests in files in parallel */ 24 | fullyParallel: true, 25 | /* Fail the build on CI if you accidentally left test.only in the source code. */ 26 | forbidOnly: !!process.env.CI, 27 | /* Retry on CI only */ 28 | retries: process.env.CI ? 2 : 0, 29 | /* Opt out of parallel tests on CI. */ 30 | workers: process.env.CI ? 1 : undefined, 31 | /* Reporter to use. See https://playwright.dev/docs/test-reporters */ 32 | reporter: "html", 33 | /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ 34 | use: { 35 | /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ 36 | actionTimeout: 0, 37 | /* Base URL to use in actions like `await page.goto('/')`. */ 38 | // baseURL: 'http://localhost:3000', 39 | 40 | /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ 41 | trace: "on-first-retry", 42 | }, 43 | 44 | /* Folder for test artifacts such as screenshots, videos, traces, etc. */ 45 | // outputDir: 'test-results/', 46 | 47 | /* Run your local dev server before starting the tests */ 48 | // webServer: { 49 | // command: 'npm run start', 50 | // port: 3000, 51 | // }, 52 | }; 53 | 54 | export default config; 55 | -------------------------------------------------------------------------------- /electron-react/src/App.tsx: -------------------------------------------------------------------------------- 1 | // import Update from '@/components/update' 2 | import React, { useContext, useEffect } from "react"; 3 | import Workshop from "./pages/Workshop"; 4 | import UIPage from "./pages/UIPage"; 5 | import { useUserComp } from "./hooks/useContextHooks"; 6 | import "./App.scss"; 7 | import FileExplorer from "./components/FileExplorer/FileExplorer"; 8 | import { ShowUIContext } from "./components/context/ShowUIContext"; 9 | import { motion } from "framer-motion"; 10 | import path from "path"; 11 | import fs from "fs"; 12 | import { PayloadType, UserActionType } from "./components/context/ContextTypes"; 13 | const os = require("os"); 14 | 15 | const pageVariants = { 16 | initial: { 17 | opacity: 0, 18 | y: 5, 19 | scale: 0.9, 20 | }, 21 | animate: { 22 | opacity: 1, 23 | y: 0, 24 | scale: 1, 25 | transition: { 26 | type: "spring", 27 | stiffness: 800, 28 | damping: 100, 29 | duration: 1, 30 | }, 31 | }, 32 | exit: { 33 | opacity: 0, 34 | y: -100, 35 | scale: 1.2, 36 | transition: { 37 | duration: 1, 38 | }, 39 | }, 40 | }; 41 | 42 | function App() { 43 | // for more info on useContext with typescript: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context 44 | const contextVal = useContext(ShowUIContext) ?? { showUI: [null, null] }; 45 | const [showUIVal, setShowUIVal] = contextVal.showUI; 46 | const { components, dispatch } = useUserComp(); 47 | 48 | useEffect(() => { 49 | const filePath = path.join(os.homedir(), "AthenaData123.json"); 50 | 51 | // Read the file's contents 52 | fs.readFile(filePath, "utf8", (err, data) => { 53 | if (err) { 54 | console.error(`Error reading file: ${err.message}`); 55 | } else { 56 | // Parse the JSON data 57 | const jsonData = JSON.parse(data); 58 | // Set user components 59 | dispatch({ type: "SET_COMPS", payload: jsonData }); 60 | } 61 | }); 62 | }, []); 63 | 64 | if (showUIVal) { 65 | return ( 66 | 74 | 75 | 76 | ); 77 | } else { 78 | return ( 79 | 87 | 88 | 89 | 90 | ); 91 | } 92 | } 93 | 94 | export default App; 95 | -------------------------------------------------------------------------------- /electron-react/src/assets/Athena_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/Athena_Icon.png -------------------------------------------------------------------------------- /electron-react/src/assets/Icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/Icon-1024.png -------------------------------------------------------------------------------- /electron-react/src/assets/Icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/Icon-128.png -------------------------------------------------------------------------------- /electron-react/src/assets/Icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/Icon-256.png -------------------------------------------------------------------------------- /electron-react/src/assets/Icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/Icon-32.png -------------------------------------------------------------------------------- /electron-react/src/assets/Icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/Icon-64.png -------------------------------------------------------------------------------- /electron-react/src/assets/athenaJS.excalidraw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/athenaJS.excalidraw -------------------------------------------------------------------------------- /electron-react/src/assets/athena_logo01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/athena_logo01.png -------------------------------------------------------------------------------- /electron-react/src/assets/logo_whitebg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/assets/logo_whitebg.png -------------------------------------------------------------------------------- /electron-react/src/assets/node.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /electron-react/src/components/FileExplorer/DirectoryComponent.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Folder } from "./FileExplorer"; 3 | 4 | interface DirectoryProps { 5 | name: string; 6 | files: Folder[]; 7 | fileParser: Function; 8 | path: string; 9 | } 10 | 11 | const DirectoryComponent: React.FC = ({ 12 | name, 13 | files, 14 | fileParser, 15 | path, 16 | }) => { 17 | // each directory component has access to it's name and files on property object 18 | // hook to tell whether button is opened or not 19 | const [isOpen, setOpen] = useState(false); 20 | 21 | const handleFolderToggle = () => { 22 | setOpen(!isOpen); 23 | }; 24 | 25 | return ( 26 |
27 | 44 | 45 | {/* when isOpen is true, render all of the subfiles of the directory component */} 46 | {isOpen && ( 47 |
48 |
49 | {/* map over each subfile */} 50 | {files.map((file) => { 51 | { 52 | /* generate subPath */ 53 | } 54 | const subPath = `${path}/${file.name}`; // create a variable to store the path 55 | { 56 | /* recursively render directory component with updated path, filename, and subfiles */ 57 | } 58 | return ( 59 |
60 | {file.directory ? ( 61 | 67 | ) : ( 68 | 74 | )} 75 |
76 | ); 77 | })} 78 |
79 | )} 80 |
81 | ); 82 | }; 83 | 84 | export default DirectoryComponent; 85 | -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/NavBar.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { motion } from 'framer-motion'; 3 | import { NavBarProps, handleToggleWindow } from './NavTypes' 4 | import { useShowUI } from '../../hooks/useContextHooks'; 5 | 6 | 7 | const NavBar: React.FC = ({handleToggleWindow}) => { 8 | const { showUI } = useShowUI(); 9 | const [showUIVal, setShowUIVal] = showUI; 10 | 11 | return ( 12 | 18 | 51 | 52 | ); 53 | }; 54 | 55 | export default NavBar; -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/NavBarUI.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { ShowUIContext } from '../context/ShowUIContext'; 3 | import { motion } from 'framer-motion'; 4 | import { useShowUI } from '../../hooks/useContextHooks'; 5 | 6 | 7 | const NavBarUI: React.FC = () => { 8 | const { showUI } = useShowUI(); 9 | const [showUIVal, setShowUIVal] = showUI; 10 | return ( 11 | 16 | 28 | 29 | ); 30 | }; 31 | 32 | export default NavBarUI; -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/NavContainerUI.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import NavBarUI from './NavBarUI'; 3 | import UIComps from '../UIWindow/UIComps'; 4 | import { NavContainerUiProps } from './NavTypes'; 5 | 6 | 7 | const NavContainerUI: React.FC = ({bg, addNode, removeNode}) => { 8 | 9 | return ( 10 | 16 | ); 17 | }; 18 | 19 | export default NavContainerUI; -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/NavTypes.ts: -------------------------------------------------------------------------------- 1 | export type NavigationContainerProps = {} 2 | 3 | 4 | 5 | export type handleToggleWindow = { 6 | props: (e: React.MouseEvent) => void; 7 | performance: (e: React.MouseEvent) => void; 8 | savedComps: (e: React.MouseEvent) => void; 9 | }; 10 | 11 | export interface NavBarProps { 12 | handleToggleWindow: handleToggleWindow 13 | } 14 | 15 | export interface NavContainerUiProps { 16 | bg: [string, React.Dispatch>], 17 | addNode: (component: object) => void, 18 | removeNode: (component: object) => void 19 | } -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/NavigationContainer.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from "react"; 2 | import PropsWindow from "../WorkshopMain/PropsWindow"; 3 | import NavBar from "./NavBar"; 4 | import PerformanceCharts from "../WorkshopMain/PerformanceCharts"; 5 | import SavedComps from "../WorkshopMain/SavedComps"; 6 | import { NavigationContainerProps, handleToggleWindow } from "./NavTypes"; 7 | 8 | const NavigationContainer: React.FC = () => { 9 | const [showPropsWindow, setShowPropsWindow] = useState(true); 10 | const [showPerformanceCharts, setShowPerformanceCharts] = 11 | useState(false); 12 | const [showSavedComps, setShowSavedComps] = useState(false); 13 | 14 | const handleToggleWindow: handleToggleWindow = { 15 | props: (e) => { 16 | setShowPropsWindow(true); 17 | setShowPerformanceCharts(false); 18 | setShowSavedComps(false); 19 | }, 20 | performance: (e) => { 21 | setShowPerformanceCharts(true); 22 | setShowPropsWindow(false); 23 | setShowSavedComps(false); 24 | }, 25 | savedComps: (e) => { 26 | setShowSavedComps(true); 27 | setShowPerformanceCharts(false); 28 | setShowPropsWindow(false); 29 | }, 30 | }; 31 | 32 | return ( 33 | 41 | ); 42 | }; 43 | 44 | export default NavigationContainer; 45 | -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/__tests__/NavBar.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, fireEvent } from '@testing-library/react'; 3 | import NavBar from '../NavBar'; 4 | import '@testing-library/jest-dom'; 5 | 6 | 7 | xdescribe('NavBar component', () => { 8 | it('should render all nav links', () => { 9 | const { getByText } = render(); 10 | expect(getByText('Edit Components')).toBeInTheDocument(); 11 | expect(getByText('Saved Components')).toBeInTheDocument(); 12 | expect(getByText('Performance')).toBeInTheDocument(); 13 | expect(getByText('UI Mode')).toBeInTheDocument(); 14 | }); 15 | 16 | it('should call handleToggleWindow function when nav links are clicked', () => { 17 | const mockHandleToggleWindow = { props: jest.fn(), savedComps: jest.fn(), performance: jest.fn() }; 18 | const { getByText } = render(); 19 | fireEvent.click(getByText('Edit Components')); 20 | expect(mockHandleToggleWindow.props).toHaveBeenCalled(); 21 | fireEvent.click(getByText('Saved Components')); 22 | expect(mockHandleToggleWindow.savedComps).toHaveBeenCalled(); 23 | fireEvent.click(getByText('Performance')); 24 | expect(mockHandleToggleWindow.performance).toHaveBeenCalled(); 25 | }); 26 | }); -------------------------------------------------------------------------------- /electron-react/src/components/Navigation/__tests__/NavBarUI.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, fireEvent } from '@testing-library/react'; 3 | import NavBarUI from '../NavBarUI'; 4 | import { ShowUIContext } from '../../context/ShowUIContext'; 5 | import '@testing-library/jest-dom'; 6 | 7 | 8 | xdescribe('NavBarUI', () => { 9 | it('should render a nav element', () => { 10 | const { getByRole } = render(); 11 | expect(getByRole('navigation')).toBeInTheDocument(); 12 | }); 13 | 14 | it('should render a list item with a link', () => { 15 | const { getByRole } = render(); 16 | expect(getByRole('listitem')).toBeInTheDocument(); 17 | expect(getByRole('link')).toBeInTheDocument(); 18 | }); 19 | 20 | it('should call the setShowUIVal function when link is clicked', () => { 21 | const setShowUIVal = jest.fn(); 22 | const { getByRole } = render(, { 23 | wrapper: ({ children }) => ( 24 | 25 | {children} 26 | 27 | ), 28 | }); 29 | const link = getByRole('link'); 30 | fireEvent.click(link); 31 | expect(setShowUIVal).toHaveBeenCalledWith(false); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /electron-react/src/components/UIWindow/ReactFlowComp.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useRef, useMemo } from "react"; 2 | import { LiveProvider, LiveEditor, LiveError, LivePreview } from "react-live"; 3 | import { NodeResizer } from "@reactflow/node-resizer"; 4 | import fetchMock from "fetch-mock"; 5 | import styled from "styled-components"; 6 | import "@reactflow/node-resizer/dist/style.css"; 7 | import { ReactFlowCompProps, component } from "./UITypes"; 8 | 9 | //Custom React Flow Component to render our saved components on the react flow UI board. 10 | const ReactFlowComp = ({ 11 | data: { component, removeNode }, 12 | selected, 13 | }: ReactFlowCompProps) => { 14 | const scope = { 15 | useState, 16 | useEffect, 17 | useRef, 18 | useMemo, 19 | styled, 20 | fetchMock, 21 | component, 22 | }; 23 | 24 | const buttonStyle = { 25 | position: "absolute", 26 | top: "-25px", 27 | right: "-20px", 28 | cursor: "pointer", 29 | padding: "0px", 30 | color: "red", 31 | fontWeight: "bold", 32 | fontSize: "2rem", 33 | }; 34 | 35 | const handleRemoveNode = (component: component): void => { 36 | removeNode(component); 37 | }; 38 | 39 | return ( 40 | <> 41 | 47 | {selected && ( 48 |
{ 51 | removeNode(component); 52 | }} 53 | > 54 | × 55 |
56 | )} 57 | { 59 | ${component.mockServer} 60 | ${component.body} 61 | return(<>${component.jsx})}`} 62 | scope={scope} 63 | > 64 | 65 | 66 | 67 | ); 68 | }; 69 | 70 | export default ReactFlowComp; 71 | -------------------------------------------------------------------------------- /electron-react/src/components/UIWindow/UIComps.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext, useEffect } from "react"; 2 | import { useUserComp } from "../../hooks/useContextHooks"; 3 | import { UICompProps, component } from "./UITypes"; 4 | 5 | //This is the UI we use to add/remove components from the react flow UI & change the background color for the react flow UI 6 | const UIComps = ({ bg, addNode, removeNode }: UICompProps) => { 7 | const { components, dispatch } = useUserComp(); 8 | const [bgColor, setBgColor] = bg; 9 | const [bgColorIn, setBgColorIn] = useState(bgColor); 10 | const [search, setSearch] = useState(""); 11 | const [showComponents, setShowComponents] = useState([ 12 | ...components, 13 | ]); 14 | 15 | useEffect((): void => { 16 | if (search) { 17 | return setShowComponents( 18 | showComponents.filter((component) => 19 | component.name.toLowerCase().includes(search.toLowerCase()) 20 | ) 21 | ); 22 | } else { 23 | return setShowComponents([...components]); 24 | } 25 | }, [search]); 26 | 27 | return ( 28 |
29 |
30 | setBgColorIn(e.target.value)} 33 | value={bgColorIn} 34 | /> 35 | 41 |
42 | setSearch(e.target.value)} 46 | placeholder="Search Component" 47 | /> 48 |
49 | {showComponents.length > 0 && 50 | showComponents.map( 51 | (component: component): JSX.Element => ( 52 |
53 | {component.name} 54 | 55 | 56 |
57 | ) 58 | )} 59 |
60 |
61 | ); 62 | }; 63 | 64 | export default UIComps; 65 | -------------------------------------------------------------------------------- /electron-react/src/components/UIWindow/UITypes.ts: -------------------------------------------------------------------------------- 1 | export type component = { 2 | name: string; 3 | jsx: string; 4 | body: string; 5 | mockServer: string; 6 | }; 7 | 8 | export type nodeData = { 9 | component: component; 10 | removeNode: (component: component) => void; 11 | }; 12 | 13 | export type nodePosition = { 14 | x: number; 15 | y: number; 16 | }; 17 | 18 | export type customNode = { 19 | id: string; 20 | type: string; 21 | position: nodePosition; 22 | data: nodeData; 23 | }; 24 | 25 | export interface UICompProps { 26 | bg: [string, React.Dispatch>]; 27 | addNode: (component: object) => void; 28 | removeNode: (component: object) => void; 29 | } 30 | 31 | export interface ReactFlowCompProps { 32 | data: nodeData; 33 | selected: boolean; 34 | } 35 | -------------------------------------------------------------------------------- /electron-react/src/components/UIWindow/ViewUI.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext, useEffect, useMemo, useRef, useCallback } from 'react'; 2 | import { Resizable } from 're-resizable'; 3 | import ReactFlow, { 4 | Controls, 5 | useNodesState, 6 | } from 'reactflow'; 7 | import 'reactflow/dist/style.css'; 8 | import NavContainerUI from '@/components/Navigation/NavContainerUI'; 9 | import ReactFlowComp from './ReactFlowComp'; 10 | import html2canvas from 'html2canvas'; 11 | import path from 'path'; 12 | import fs from 'fs'; 13 | const os = require('os'); 14 | import { component, customNode, nodeData } from './UITypes'; 15 | 16 | const nodeTypes = {customComp: ReactFlowComp}; 17 | 18 | const ViewUI = () => { 19 | const [ nodes, setNodes, onNodesChange ] = useNodesState([]); 20 | const [ bgColor, setBgColor ] = useState('#D0DBFE'); 21 | 22 | const divRef = useRef(null); 23 | 24 | const flowStyle = { 25 | background: bgColor 26 | }; 27 | 28 | //Add a node to the react flow UI 29 | const addNode = (component: component): void => { 30 | //pass in removeNode function as a prop to be destructured in the ReactFlowComp component 31 | const newNode: customNode = { id: component.name, type: 'customComp', position: { x: 200, y: 200 }, data: {component, removeNode}} 32 | return setNodes([...nodes, newNode]); 33 | }; 34 | 35 | //Remove a specific node from the react flow UI (tied to that specific components remove button in UIComps.jsx) 36 | const removeNode = (component: component): void => { 37 | return setNodes(prevNodes => prevNodes.filter((node) => node.id !== component.name)); 38 | }; 39 | 40 | //Take a screenshot of the react flow UI div. 41 | const captureScreenshot = (): void => { 42 | html2canvas(divRef.current as HTMLElement).then(canvas => { 43 | const image: string = canvas.toDataURL('image/png'); 44 | const timestamp: number = Date.now(); 45 | const randomNumber: number = Math.floor(Math.random() * 100000); 46 | const fileName: string = `AthenaScreenshot_${timestamp}_${randomNumber}.png`; 47 | const filePath: string = path.join(os.homedir(), 'Downloads', fileName); 48 | fs.writeFile(filePath, image.replace(/^data:image\/png;base64,/, ''), 'base64', err => { 49 | if (err) throw err; 50 | alert(`Screenshot saved as ${fileName}`); 51 | }); 52 | }); 53 | }; 54 | 55 | return( 56 | <> 57 | 76 | 83 | 84 | 85 | 86 | 87 | void} addNode = {addNode as () => void}/> 88 | 89 | ); 90 | }; 91 | 92 | export default ViewUI; -------------------------------------------------------------------------------- /electron-react/src/components/UIWindow/__tests__/UIComps.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen, fireEvent } from '@testing-library/react'; 3 | import UIComps from '../UIComps'; 4 | import { UserCompProvider } from '../../context/UserCompContext'; 5 | 6 | xdescribe('UIComps component', () => { 7 | // const mockValue = { 8 | // components: [ 9 | // { name: 'Component 1', body: 'Const var1 = 1', jsx: '
Component JSX 1
', mockServer: null }, 10 | // { name: 'Component 2', body: 'Const var2 = 2', jsx: '
Component JSX 2
', mockServer: null }, 11 | // ], 12 | // dispatch: jest.fn(), 13 | // }; 14 | test.todo('renders component names' 15 | // , () => { 16 | // render( 17 | // 18 | // 19 | // 20 | // ); 21 | 22 | // const comp1 = screen.getByText(/Component 1/i); 23 | // const comp2 = screen.getByText(/Component 2/i); 24 | // expect(comp1.textContent).toBe('Component 1'); 25 | // expect(comp2.textContent).toBe('Component 2'); 26 | // } 27 | ); 28 | 29 | test.todo('calls addNode when "Add" button is clicked' 30 | // , () => { 31 | // const mockAddNode = jest.fn(); 32 | // render( 33 | // 34 | // 35 | // 36 | // ); 37 | 38 | // const add1Button = screen.getByText(/Add/i, { selector: 'button' }); 39 | // fireEvent.click(add1Button); 40 | // expect(mockAddNode).toHaveBeenCalledTimes(1); 41 | // expect(mockAddNode).toHaveBeenCalledWith(mockValue.components[0]); 42 | // } 43 | ); 44 | 45 | test.todo('calls removeNode when "Remove" button is clicked' 46 | // , () => { 47 | // const mockRemoveNode = jest.fn(); 48 | // render( 49 | // 50 | // 51 | // 52 | // ); 53 | 54 | // const remove2Button = screen.getByText(/Remove/i, { selector: 'button' }); 55 | // fireEvent.click(remove2Button); 56 | // expect(mockRemoveNode).toHaveBeenCalledTimes(1); 57 | // expect(mockRemoveNode).toHaveBeenCalledWith(mockValue.components[1]); 58 | // } 59 | ); 60 | }); 61 | -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/PerformanceCharts.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { Bar } from 'react-chartjs-2'; 3 | import { usePerformance } from '../../hooks/useContextHooks'; 4 | import { motion } from 'framer-motion'; 5 | import { 6 | Chart as ChartJS, 7 | CategoryScale, 8 | LinearScale, 9 | BarElement, 10 | Tooltip, 11 | } from 'chart.js'; 12 | ChartJS.register( 13 | CategoryScale, 14 | LinearScale, 15 | BarElement, 16 | Tooltip 17 | ); 18 | const transition = { 19 | type: 'spring', 20 | damping: 30, 21 | stiffness: 300, 22 | duration: 1 23 | }; 24 | import { performanceData } from '../context/ContextTypes'; 25 | 26 | 27 | const PerformanceCharts = () => { 28 | const perfContext = usePerformance(); 29 | const [ profilerData, setProfilerData ] = perfContext.performanceData; 30 | 31 | const getActualDurationData = (): number[] => { 32 | return profilerData.map((data: performanceData ) => data.actualDuration); 33 | }; 34 | const getIds = (): string[] => { 35 | return profilerData.map((data: performanceData ) => data.renderName); 36 | }; 37 | 38 | const handleUndo = (): void => { 39 | setProfilerData && setProfilerData(profilerData.slice(0,profilerData.length - 1)); 40 | }; 41 | 42 | const handleReset = (): void => { 43 | setProfilerData && setProfilerData([]); 44 | }; 45 | 46 | if (profilerData.length > 0){ 47 | return( 48 | 53 |

Component Render Times (ms)

54 | 85 | 86 | 87 |
88 | ); 89 | } 90 | else{ 91 | return( 92 | 97 |

Save Render Data to Generate Bar Graph

98 |
99 | ); 100 | } 101 | }; 102 | 103 | export default PerformanceCharts; -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/PropsWindow.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext } from 'react'; 2 | import { DetailsContext } from '../context/DetailsContext'; 3 | import { MockFetchContext } from '../context/MockFetchContext'; 4 | import { PerformanceContext } from '../context/PerformanceContext'; 5 | import { 6 | usePerformance, 7 | useMockFetch, 8 | useDetails, 9 | useUserComp 10 | } from '@/hooks/useContextHooks'; 11 | import {motion} from 'framer-motion'; 12 | import AceEditor from 'react-ace'; 13 | import 'ace-builds/src-noconflict/mode-javascript'; 14 | import 'ace-builds/src-noconflict/mode-json'; 15 | import 'ace-builds/src-noconflict/mode-jsx'; 16 | import 'ace-builds/src-noconflict/theme-monokai'; 17 | import 'ace-builds/src-noconflict/ext-language_tools'; 18 | import 'ace-builds/src-noconflict/worker-javascript'; 19 | import 'ace-builds/src-noconflict/worker-json'; 20 | 21 | // https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-d-ts.html 22 | // exposing an any type for the ace editor on the window 23 | declare global { 24 | interface Window { 25 | ace: any; 26 | } 27 | } 28 | 29 | //Need these to make workers function for ace editor (allows linting and other code editor functionality) 30 | window.ace.config.setModuleUrl('ace/mode/javascript_worker', '../../node_modules/ace-builds/src-noconflict/worker-javascript.js'); 31 | window.ace.config.setModuleUrl('ace/mode/json_worker', '../../node_modules/ace-builds/src-noconflict/worker-json.js'); 32 | 33 | //Framer motion variants 34 | const fadeInVariants = { 35 | hidden: { opacity: 0.9 }, 36 | visible: { opacity: 1 }, 37 | }; 38 | 39 | const transition = { 40 | duration: 2, 41 | }; 42 | 43 | const transitionPage = { 44 | type: "spring", 45 | damping: 30, 46 | stiffness: 300, 47 | duration: 1 48 | }; 49 | 50 | //form for adjusting component 51 | const PropsWindow = () => { 52 | //Global state: temp versions are for the text editor states 53 | const { compBody, compJSX, tempCompBody, tempCompJSX} = useDetails(); 54 | const [compBodyVal, setCompBodyVal] = compBody; 55 | const [compJSXVal, setCompJSXVal] = compJSX; 56 | const { mockServer } = useMockFetch(); 57 | const [ mockServerVal, setMockServerVal ] = mockServer; 58 | // States for text editors 59 | const [ tempCompBodyVal, setTempCompBodyVal ] = tempCompBody; 60 | const [ tempCompJSXVal, setTempCompJSXVal ] = tempCompJSX; 61 | const [ tempMockServer, setTempMockServer ] = useState(`fetchMock.mock('*', {data: 'mock data'}, { overwriteRoutes: true });`) 62 | // toggle states for windows (props, state, mockFetch) 63 | const [bodyWindowVisible, setBodyWindowVisible] = useState(true); 64 | const [mockServerWindowVisible, setMockServerWindowVisible] = useState(false); 65 | //Key count to force remount on component update -> this is used for the React Profiler API in ViewComponent.jsx 66 | const { keyCount } = usePerformance(); 67 | const [ keyCountVal , setKeyCountVal] = keyCount; 68 | //state and dispatch for saved user components 69 | const {components, dispatch} = useUserComp(); 70 | const [ saveName, setSaveName ] = useState('my_component'); 71 | const [ checkSaveModal, setCheckSaveModal ] = useState(false); 72 | 73 | //Handle the submit of the create props form 74 | const handleSubmit = (e: React.MouseEvent): void => { 75 | e.preventDefault(); 76 | //On form submission (Update View button), we set the states for the component renderer 77 | //We also adjust keyCount so that we measure a new render time with react profiler API 78 | try { 79 | setCompBodyVal(tempCompBodyVal); 80 | setCompJSXVal(tempCompJSXVal); 81 | setMockServerVal(tempMockServer); 82 | setTimeout(() => setKeyCountVal(keyCountVal + 1), 0); 83 | } catch (error) { 84 | console.log(error); 85 | } 86 | }; 87 | 88 | //Check if component has already been saved when we press save component 89 | const checkCompExist = (): void => { 90 | for (let i = 0; i < components.length; i++){ 91 | if (components[i].name === saveName) return setCheckSaveModal(true); 92 | } 93 | return handleSave(); 94 | }; 95 | 96 | //If user says they want to overwrite component -> do this 97 | const handleOverWriteYes = (): void => { 98 | try{ 99 | //Overwrite the object for the existing component in the UserComponents global state 100 | dispatch({type: 'EDIT_COMPS', payload: { 101 | name: saveName, 102 | jsx: compJSXVal, 103 | body: compBodyVal, 104 | mockServer: mockServerVal, 105 | }}); 106 | //Close the modal 107 | setCheckSaveModal(false); 108 | } catch(error){ 109 | console.log(error); 110 | } 111 | }; 112 | 113 | //If user says they don't want to overwrite component 114 | const handleOverWriteNo = (): void => { 115 | //close modal 116 | setCheckSaveModal(false); 117 | }; 118 | 119 | //Save current component by adding to the UserComponent array (via reducer) 120 | const handleSave = (): void => { 121 | try{ 122 | dispatch({type: 'ADD_COMPS', payload: { 123 | name: saveName, 124 | jsx: compJSXVal, 125 | body: compBodyVal, 126 | mockServer: mockServerVal, 127 | }}); 128 | } catch(error){ 129 | console.log(error); 130 | } 131 | }; 132 | 133 | // handle toggling the body and mockServer containers 134 | const handleToggleWindow = { 135 | body : (e: React.MouseEvent): void => { 136 | setBodyWindowVisible(true); 137 | setMockServerWindowVisible(false); 138 | }, 139 | mockServer: (e: React.MouseEvent): void => { 140 | setBodyWindowVisible(false); 141 | setMockServerWindowVisible(true); 142 | } 143 | }; 144 | 145 | // ace editor style options object 146 | const styleOptions = { 147 | width: '100%', 148 | height: '100%', 149 | }; 150 | 151 | return ( 152 | 158 |
159 | {checkSaveModal && 160 |
161 |

A component with this name already exists, overwrite component?

162 |
163 | 164 | 165 |
166 | } 167 | setSaveName(e.target.value)} /> 170 | 171 |
172 |
173 |
174 | 175 |
176 | {/* toggleable containers */} 177 |
178 | {bodyWindowVisible && 179 | 186 | 187 | 193 | setTempCompBodyVal(value)} 199 | value={tempCompBodyVal} 200 | editorProps={{ $blockScrolling: true }} 201 | width={styleOptions.width} 202 | height={styleOptions.height} 203 | setOptions={{ 204 | useWorker: true, 205 | enableBasicAutocompletion: true, 206 | enableLiveAutocompletion: true, 207 | }} 208 | /> 209 | 210 | } 211 | {mockServerWindowVisible && 212 | 220 | 221 | 227 | setTempMockServer(value)} 233 | value={tempMockServer} 234 | editorProps={{ $blockScrolling: true }} 235 | width={styleOptions.width} 236 | height={styleOptions.height} 237 | /> 238 | 239 | } 240 |
241 |
242 | 243 | setTempCompJSXVal(value)} 249 | value={tempCompJSXVal} 250 | editorProps={{ $blockScrolling: true }} 251 | width={styleOptions.width} 252 | height={styleOptions.height} 253 | /> 254 |
255 |
256 |
257 |
258 | ); 259 | 260 | }; 261 | 262 | export default PropsWindow; -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/SavedComps.tsx: -------------------------------------------------------------------------------- 1 | import React, {useState, useEffect, useContext} from 'react'; 2 | import { useUserComp, usePerformance, useMockFetch, useDetails } from '../../hooks/useContextHooks'; 3 | const { ipcRenderer } = require('electron'); 4 | import path from 'path'; 5 | import fs from 'fs'; 6 | const os = require('os'); 7 | import { motion } from 'framer-motion'; 8 | import { componentsData } from './WorkshopTypes'; 9 | 10 | const transition = { 11 | type: "spring", 12 | damping: 30, 13 | stiffness: 300, 14 | duration: 1 15 | }; 16 | 17 | const SavedComps = () => { 18 | const {components, dispatch} = useUserComp(); 19 | //Global state to handle component in the viewer 20 | const { compBody, compJSX, tempCompBody, tempCompJSX } = useDetails(); 21 | const [compBodyVal, setCompBodyVal] = compBody; 22 | const [compJSXVal, setCompJSXVal] = compJSX; 23 | const [ tempCompBodVal, setTempCompBodyVal ] = tempCompBody; 24 | const [ tempCompJSXVal, setTempCompJSXVal ] = tempCompJSX; 25 | const { mockServer } = useMockFetch(); 26 | const [ mockServerVal, setMockServerVal ] = mockServer; 27 | 28 | const { keyCount } = usePerformance(); 29 | const [ keyCountVal , setKeyCountVal] = keyCount; 30 | 31 | const [ search, setSearch ] = useState('') 32 | const [ showComponents, setShowComponents ] = useState([...components]) 33 | 34 | useEffect((): void => { 35 | if (search){ 36 | return setShowComponents(showComponents.filter(component => component.name.toLowerCase().includes(search.toLowerCase()))) 37 | } 38 | else{ 39 | return setShowComponents([...components]) 40 | } 41 | 42 | }, [search, components]) 43 | 44 | //Save component JSON 45 | const saveJson = (): void => { 46 | const data = components; 47 | //file AthenaData123.json in home directory 48 | const filePath = path.join(os.homedir(), 'AthenaData123.json'); 49 | //Stringify the data 50 | const json = JSON.stringify(data, null, 2); 51 | //save the json to the file 52 | fs.writeFile(filePath, json, 'utf8', (err) => { 53 | if (err) { 54 | console.error(`Error writing file: ${err.message}`); 55 | } else { 56 | console.log(`File saved to ${filePath}`); 57 | } 58 | }); 59 | }; 60 | 61 | 62 | 63 | //Render the selected component by setting the states that the renderer uses 64 | const renderComponent = (component: componentsData): void => { 65 | setCompBodyVal(component.body); 66 | setCompJSXVal(component.jsx); 67 | setTempCompBodyVal(component.body); 68 | setTempCompJSXVal(component.jsx); 69 | setMockServerVal(component.mockServer); 70 | setTimeout(() => {setKeyCountVal(keyCountVal + 1)}, 0); 71 | }; 72 | 73 | //Export file as JSX (we build the component in the template literal) 74 | function handleExportClick(component: componentsData): void { 75 | const fileContent = 76 | ` 77 | import React, { useState, useEffect } from 'react'; 78 | 79 | const ${component.name} = () => { 80 | ${component.body} 81 | return( 82 | <> 83 | ${component.jsx} 84 | 85 | ) 86 | } 87 | 88 | export default ${component.name} 89 | `; 90 | //Check electron/main/index.tsx at the bottom to see logic for this 91 | ipcRenderer.send('save-file-dialog', fileContent); 92 | } 93 | 94 | //Delete the selected component 95 | const handleDelete = (component: componentsData): void => { 96 | dispatch({type: 'DELETE_COMPS', payload: component}); 97 | }; 98 | 99 | return( 100 | 106 | 107 | setSearch(e.target.value)} 111 | placeholder='Search Components' 112 | /> 113 |
114 | {showComponents.length > 0 && showComponents.map( (component: componentsData) => ( 115 |
116 | {component.name} 117 | 118 | 119 | 120 |
121 | ))} 122 |
123 |
124 | ); 125 | }; 126 | 127 | export default SavedComps; -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/ViewComponent.tsx: -------------------------------------------------------------------------------- 1 | import React, { Profiler, useContext, useState, useEffect, useRef, useMemo } from 'react'; 2 | import { useDetails, useMockFetch, usePerformance} from '../../hooks/useContextHooks' 3 | import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live'; 4 | import fetchMock from 'fetch-mock'; 5 | import styled from 'styled-components'; 6 | import { MockFetchContext } from '../context/MockFetchContext'; 7 | import { Resizable } from 're-resizable'; 8 | import { performanceData } from '../context/ContextTypes'; 9 | import { profilerData } from './WorkshopTypes'; 10 | import AthenaLogoSvg from '../framerMotion/AthenaLogo'; 11 | 12 | const ViewComponent = () => { 13 | const { compBody, compJSX } = useDetails(); 14 | const { mockServer } = useContext(MockFetchContext) ?? {mockServer: [null, null]}; 15 | const { keyCount, performanceData } = usePerformance(); 16 | const [ performanceDataArr, setPerformanceDataArr] = performanceData; 17 | const [ profilerData, setProfilerData ] = useState(null); 18 | const [ renderName, setRenderName ] = useState(''); 19 | 20 | // Set render data for the component being rendered. We only measure the stats for mounting phase 21 | // could look in React.Profiler d.ts for the typing 22 | const handleProfilerData = (id: string, phase: string, actualDuration: number, baseDuration: number, startTime: number, commitTime: number): void => { 23 | if (phase === 'mount'){ 24 | setProfilerData({ 25 | id, 26 | phase, 27 | actualDuration, 28 | baseDuration, 29 | startTime, 30 | commitTime, 31 | }); 32 | } 33 | }; 34 | 35 | //If we want to add the render time to our chart, we press the button and it adds the data to the graph data array. 36 | const updateGraph = (): void => { 37 | setPerformanceDataArr([ 38 | ...performanceDataArr, 39 | {renderName: renderName, ...profilerData} as performanceData 40 | ]); 41 | }; 42 | 43 | 44 | //This is the code for the react component we want to render. 45 | const string = `() => { 46 | ${mockServer[0]} 47 | ${compBody[0]} 48 | return( 49 | <> 50 | ${compJSX[0]} 51 | 52 | ) 53 | }`; 54 | 55 | //These allow us to use common react hooks and styled + fetchMock libraries with react-live (the library we are using to render components) 56 | let scope = {useState, useEffect, useRef, useMemo, styled}; 57 | // this is the typing library: @types/fetch-mock 58 | // @ts-ignore 59 | if (mockServer[0]) scope = {useState, useEffect, useRef, useMemo, styled, fetchMock}; 60 | 61 | return ( 62 | 81 | ); 82 | }; 83 | 84 | export default ViewComponent; -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/WorkshopTypes.ts: -------------------------------------------------------------------------------- 1 | export type componentsData = { 2 | name: string, 3 | jsx: string, 4 | body: string, 5 | mockServer: string, 6 | }; 7 | 8 | export type profilerData = { 9 | id: string, 10 | phase: string, 11 | actualDuration: number, 12 | baseDuration: number, 13 | startTime: number, 14 | commitTime: number, 15 | }; -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/__tests__/PerformanceCharts.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, fireEvent } from '@testing-library/react'; 3 | import PerformanceCharts from '../PerformanceCharts'; 4 | import { PerformanceContext, PerformanceProvider } from '../../context/PerformanceContext'; 5 | import '@testing-library/jest-dom'; 6 | 7 | //Need to fix this test file, there are some issues with Chart.js using an object not available within the test 8 | //Look into Canvas 9 | 10 | describe('PerformanceCharts', () => { 11 | it('renders the "Save Render Data" message when no data is provided', () => { 12 | const { getByText } = render( 13 | 14 | 15 | 16 | ); 17 | expect(getByText('Save Render Data to Generate Bar Graph')).toBeInTheDocument(); 18 | }); 19 | 20 | it('renders a bar graph when data is provided', () => { 21 | const mockData = [ { renderName: 'Render 1', actualDuration: 2, }, { renderName: 'Render 2', actualDuration: 1, }, ]; 22 | 23 | // Mock the getContext method of the canvas element 24 | 25 | // Mock the setState function for the performance data 26 | const setPerformanceData = jest.fn(); 27 | 28 | // Render PerformanceCharts component with mock data and mock setState function 29 | const { getByTestId } = render( 30 | 31 | 32 | 33 | ); 34 | 35 | // Assert that the chart is rendered 36 | expect(getByTestId('bar-chart')).toBeInTheDocument(); 37 | }); 38 | 39 | }) 40 | -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/__tests__/SavedComps.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen, fireEvent } from '@testing-library/react'; 3 | import { DetailsContext } from '../../context/DetailsContext'; 4 | import { MockFetchContext } from '../../context/MockFetchContext'; 5 | import { PerformanceContext } from '../../context/PerformanceContext'; 6 | import { UserCompContext } from '../../context/UserCompContext'; 7 | import SavedComps from '../SavedComps'; 8 | import '@testing-library/jest-dom'; 9 | 10 | // create a mock context value 11 | const mockComponents = [ 12 | { name: 'Component 1', body: 'Const var1 = 1', jsx: '
Component JSX 1
', mockServer: null }, 13 | { name: 'Component 2', body: 'Const var2 = 2', jsx: '
Component JSX 2
', mockServer: null }, 14 | ]; 15 | const mockValue = { 16 | components: mockComponents, 17 | dispatch: jest.fn(), 18 | }; 19 | const mockDetailsValue = { 20 | compBody: ['', jest.fn()], 21 | compJSX: ['', jest.fn()], 22 | tempCompBody: ['', jest.fn()], 23 | tempCompJSX: ['', jest.fn()], 24 | }; 25 | const mockMockFetchValue = { 26 | mockServer: [null, jest.fn()], 27 | }; 28 | const mockPerformanceValue = { 29 | keyCount: [0, jest.fn()], 30 | }; 31 | 32 | describe('SavedComps component', () => { 33 | test('renders component names', () => { 34 | render( 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | ); 45 | screen.debug() 46 | const comp1 = screen.getByText(/Component 1/i); 47 | const comp2 = screen.getByText(/Component 2/i); 48 | expect(comp1.textContent).toBe('Component 1'); 49 | expect(comp2.textContent).toBe('Component 2'); 50 | }); 51 | 52 | test('clicking on render button displays component preview', () => { 53 | // test to ensure that clicking on the render button displays the component preview 54 | render( 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | ); 65 | const comp1 = screen.getByText(/Component 1/i); 66 | const comp2 = screen.getByText(/Component 2/i); 67 | const renderButton1 = screen.getAllByText(/Render/)[0]; 68 | const renderButton2 = screen.getAllByText(/Render/)[1]; 69 | fireEvent.click(renderButton1); 70 | expect(mockMockFetchValue.mockServer[1]).toHaveBeenCalledWith(mockComponents[0].mockServer); 71 | fireEvent.click(renderButton2); 72 | expect(mockMockFetchValue.mockServer[1]).toHaveBeenCalledWith(mockComponents[1].mockServer); 73 | }); 74 | 75 | 76 | test('calls dispatch function when delete button is clicked', () => { 77 | render( 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ); 88 | const deleteButtons = screen.getAllByText(/delete/i); 89 | fireEvent.click(deleteButtons[0]); 90 | expect(mockValue.dispatch).toHaveBeenCalled(); 91 | }); 92 | 93 | test('calls details context functions when render button is clicked', () => { 94 | render( 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | ); 105 | const renderButtons = screen.getAllByText(/render/i); 106 | fireEvent.click(renderButtons[0]); 107 | expect(mockDetailsValue.compBody[1]).toHaveBeenCalledWith(mockComponents[0].body); 108 | expect(mockDetailsValue.compJSX[1]).toHaveBeenCalledWith(mockComponents[0].jsx); 109 | }); 110 | 111 | test('searches for component names', () => { 112 | render( 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | ); 123 | 124 | const searchInput = screen.getByPlaceholderText('Search Components'); 125 | fireEvent.change(searchInput, { target: { value: 'Component 1' } }); 126 | 127 | const comp1 = screen.getByText(/Component 1/i); 128 | const comp2 = screen.queryByText(/Component 2/i); 129 | expect(comp1).toBeInTheDocument(); 130 | expect(comp2).toBeNull(); 131 | }); 132 | }); 133 | 134 | -------------------------------------------------------------------------------- /electron-react/src/components/WorkshopMain/__tests__/ViewComponent.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen, waitFor } from '@testing-library/react'; 3 | import userEvent from '@testing-library/user-event'; 4 | import '@testing-library/jest-dom'; 5 | import { UserCompProvider } from '../../context/UserCompContext' 6 | import { DetailsProvider } from '../../context/DetailsContext'; 7 | import { PerformanceProvider } from '../../context/PerformanceContext'; 8 | import { MockFetchProvider } from '../../context/MockFetchContext'; 9 | import ViewComponent from '../ViewComponent'; 10 | 11 | jest.mock('fetch-mock', () => jest.fn()); 12 | 13 | const mockProviderValues = { 14 | mockUserCompValue : { 15 | components: [ 16 | { name: 'Component 1', body: 'Const var1 = 1', jsx: '
Component JSX 1
', mockServer: null }, 17 | { name: 'Component 2', body: 'Const var2 = 2', jsx: '
Component JSX 2
', mockServer: null }, 18 | ], 19 | dispatch: jest.fn(), 20 | }, 21 | mockDetailsValue : { 22 | compBody: ['', jest.fn()], 23 | compJSX: ['', jest.fn()], 24 | tempCompBody: ['', jest.fn()], 25 | tempCompJSX: ['', jest.fn()], 26 | }, 27 | mockMockFetchValue : { 28 | mockServer: [false, jest.fn()], 29 | }, 30 | mockPerformanceValue : { 31 | keyCount: [0, jest.fn()], 32 | }, 33 | } 34 | 35 | function renderViewComponent ({ 36 | mockUserCompValue, 37 | mockDetailsValue, 38 | mockPerformanceValue, 39 | mockMockFetchValue 40 | }) { 41 | return render( 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ); 52 | }; 53 | 54 | describe('ViewComponent component', () => { 55 | it('should render successfully', () => { 56 | renderViewComponent(mockProviderValues); 57 | const element = screen.getByText(/Render Time/i); 58 | expect(element).toBeInTheDocument(); 59 | }); 60 | 61 | it('should be able to input a render name', async () => { 62 | renderViewComponent(mockProviderValues); 63 | const inputElement = screen.getByRole('textbox'); 64 | await userEvent.type(inputElement, 'foo'); 65 | expect(inputElement).toBeInTheDocument(); 66 | expect(inputElement).toHaveValue('foo'); 67 | }); 68 | 69 | it('should have a button that on click should display a render time', async () => { 70 | renderViewComponent(mockProviderValues); 71 | await userEvent.click(screen.getByRole('button', {name: /Add Data/i})); 72 | expect(screen.getByText(/\d+ ms/i)).toBeInTheDocument(); 73 | }); 74 | 75 | // it('should render an element (from a context)', async () => { 76 | // const tempProviderValues = { 77 | // ...mockProviderValues, 78 | // mockDetailsValue: { 79 | // ...mockProviderValues.mockDetailsValue, 80 | // compJSX: ['

hello

' ,jest.fn()] 81 | // } 82 | // }; 83 | // console.log(tempProviderValues.mockDetailsValue.compJSX[0]); 84 | // renderViewComponent(tempProviderValues); 85 | // screen.debug(); 86 | // expect(screen.getByText(/hello/i)).toBeInTheDocument(); 87 | // }); 88 | }); -------------------------------------------------------------------------------- /electron-react/src/components/context/ContextTypes.ts: -------------------------------------------------------------------------------- 1 | import { Dispatch, SetStateAction } from "react" 2 | 3 | export interface DetailsContextType { 4 | compJSX: [string, Dispatch>], 5 | compBody:[string, Dispatch>], 6 | tempCompBody:[string, Dispatch>], 7 | tempCompJSX:[string, Dispatch>] 8 | } 9 | 10 | export interface MockFetchContextType { 11 | mockServer:[string | null, Dispatch>] 12 | } 13 | 14 | export type performanceData = { 15 | renderName: string, 16 | id: string, 17 | phase: string, 18 | actualDuration: number, 19 | baseDuration: number, 20 | startTime: number, 21 | commitTime: number, 22 | }; 23 | 24 | export interface PerformanceContextType { 25 | performanceData: [performanceData[], Dispatch>], 26 | keyCount: [number, Dispatch>] 27 | } 28 | 29 | export interface ShowUIType { 30 | showUI: [boolean , Dispatch>] 31 | } 32 | 33 | export interface UserComponent { 34 | name: string; 35 | } 36 | 37 | export interface UserCompType { 38 | components: PayloadType[]; 39 | dispatch: Function 40 | } 41 | 42 | // type Overloading for useReducer Actions: https://stackoverflow.com/questions/73902445/overloading-payload-in-usereducer-hook-typescript 43 | export type UserActionType = { 44 | type: 'SET_COMPS'; 45 | payload: PayloadType[] 46 | } | { 47 | type: 'ADD_COMPS' | 'DELETE_COMPS' | 'EDIT_COMPS'; 48 | payload: PayloadType; 49 | } 50 | 51 | export interface UserStateType { 52 | components: PayloadType[]; 53 | } 54 | 55 | export interface PayloadType { 56 | name: string, 57 | jsx: string, 58 | body: string, 59 | mockServer: string 60 | } -------------------------------------------------------------------------------- /electron-react/src/components/context/DetailsContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, createContext, Dispatch, SetStateAction } from 'react'; 2 | import { DetailsContextType } from './ContextTypes'; 3 | 4 | 5 | export const DetailsContext = createContext(null); 6 | //These are the details that define the component that gets rendered on the screen 7 | export const DetailsProvider = ({ children } : any) => { 8 | //States for the component in the renderer 9 | const [compBody, setCompBody] = useState( 10 | ` 11 | const [count, setCount] = useState(1) 12 | const var1 = 1 13 | const handleClick = () => console.log('button clicked') 14 | ` 15 | ); 16 | const [compJSX, setCompJSX] = useState( 17 | '' 18 | ); 19 | //States for the code written in the code editors, it gets transferred to the states above when we press the update view button in PropsWindow.jsx 20 | const [ tempCompBody, setTempCompBody ] = useState( 21 | `const [count, setCount] = useState(1) 22 | const var1 = 1 23 | const handleClick = () => console.log('button clicked') 24 | ` 25 | ); 26 | const [ tempCompJSX, setTempCompJSX ] = useState( 27 | '' 28 | ); 29 | 30 | return ( 31 | 39 | {children} 40 | 41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /electron-react/src/components/context/MockFetchContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, createContext, Dispatch, SetStateAction } from 'react'; 2 | import { MockFetchContextType } from './ContextTypes'; 3 | 4 | 5 | export const MockFetchContext = createContext(null); 6 | 7 | export const MockFetchProvider = ({ children } : any) => { 8 | //mockFetch information, initially set to null in case the user does not want to use a mock server 9 | const [ mockServer, setMockServer ] = useState(null); 10 | 11 | return( 12 | 17 | {children} 18 | 19 | ); 20 | }; -------------------------------------------------------------------------------- /electron-react/src/components/context/PerformanceContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, createContext, Dispatch, SetStateAction } from 'react'; 2 | import { PerformanceContextType, performanceData } from './ContextTypes'; 3 | 4 | export const PerformanceContext = createContext(null); 5 | 6 | //These are the states used with the react profiler API to store render data that is saved. This data is then charted using Chart.js in PerformanceCharts.jsx 7 | export const PerformanceProvider = ({ children }: any) => { 8 | //This state holds the performance data that gets graphed 9 | const [performanceData, setPerformanceData] = useState([]); 10 | //This state changes the key of the react profiler component to force a remount and get a new render time for the mounting event. 11 | const [keyCount, setKeyCount] = useState(0); 12 | 13 | return ( 14 | 20 | {children} 21 | 22 | ); 23 | }; -------------------------------------------------------------------------------- /electron-react/src/components/context/ShowUIContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, createContext, SetStateAction, Dispatch } from 'react'; 2 | import { ShowUIType } from './ContextTypes'; 3 | 4 | 5 | export const ShowUIContext = createContext(null); 6 | 7 | //This state is used to determine if we show the UI page or the Component page (UI Mode/Component mode) 8 | export const ShowUIProvider = ({ children } : any) => { 9 | const [showUI, setShowUI] = useState(false); 10 | 11 | return ( 12 | 17 | {children} 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /electron-react/src/components/context/UserCompContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, ReducerWithoutAction, useReducer } from 'react'; 2 | import { UserCompType, UserActionType, UserStateType, PayloadType } from './ContextTypes'; 3 | 4 | export const UserCompContext = createContext(null); 5 | 6 | //Comp reducer which defines various actions that can be made to mutate comp state 7 | export const UserCompReducer = (state: UserStateType, action: UserActionType): UserStateType => { 8 | switch (action.type) { 9 | //useEffect in App.tsx gets user's component library from local system and sets the component array content using the SET_COMPS action type 10 | case 'SET_COMPS': 11 | return { 12 | components: action.payload 13 | }; 14 | //When a user saves a component, it gets added to the array as an additional object 15 | case 'ADD_COMPS': 16 | return { 17 | components: [action.payload, ...state.components] 18 | }; 19 | //Filter to find the specific component to be deleted, reassign state to be the array that does not contain that component 20 | case 'DELETE_COMPS': 21 | return { 22 | components: state.components.filter((comp) => comp.name !== action.payload.name) 23 | }; 24 | //If the user wants to overwrite a component that exists already, we use this action type 25 | case 'EDIT_COMPS': 26 | return { 27 | components: state.components.map((comp) => comp.name === action.payload.name ? action.payload : comp) 28 | }; 29 | //Default case return state 30 | default: 31 | return state; 32 | } 33 | }; 34 | 35 | //Define context provider -> reducer is UserCompReducer and initial argument is components 36 | export const UserCompProvider = ({ children }: any) => { 37 | 38 | // Currently not typing the react reducer, will reroute to this to fully implement typing once get better hang of it. 39 | const [state, dispatch] = useReducer(UserCompReducer, { components: [] }); 40 | 41 | //Provider passes state and dispatch props to children 42 | return ( 43 | 44 | {children} 45 | 46 | ); 47 | }; -------------------------------------------------------------------------------- /electron-react/src/components/framerMotion/AthenaSvg.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { motion } from "framer-motion"; 3 | 4 | const pathVariants = { 5 | hidden: { 6 | pathLength: 0, 7 | opacity: 0 8 | }, 9 | visible: { 10 | pathLength: 1, 11 | opacity: 1 12 | } 13 | }; 14 | 15 | //This component is the Athena icon that gets drawn at the top of the screen on load for component mode 16 | //It uses framer motion, where d is the path that the pen stroke follows (M moves the pen without drawing anything, L draws from the point that 17 | //the pen is at currently to the point specified after the L) 18 | const AthenaSvg = () => { 19 | 20 | return( 21 |
22 | 28 | 42 | 56 | 70 | 71 |
72 | ); 73 | }; 74 | 75 | export default AthenaSvg; -------------------------------------------------------------------------------- /electron-react/src/components/update/Modal/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react' 2 | import { createPortal } from 'react-dom' 3 | import styles from './modal.module.scss' 4 | 5 | const ModalTemplate: React.FC void 11 | onOk?: () => void 12 | width?: number 13 | }>> = props => { 14 | const { 15 | title, 16 | children, 17 | footer, 18 | cancelText = 'Cancel', 19 | okText = 'OK', 20 | onCancel, 21 | onOk, 22 | width = 530, 23 | } = props 24 | 25 | return ( 26 |
27 |
28 |
29 |
30 |
31 |
{title}
32 | 36 | 40 | 41 | 42 | 43 | 44 |
45 |
{children}
46 | {typeof footer !== 'undefined' ? ( 47 |
48 | 49 | 50 |
51 | ) : footer} 52 |
53 |
54 |
55 | ) 56 | } 57 | 58 | const Modal = (props: Parameters[0] & { open: boolean }) => { 59 | const { open, ...omit } = props 60 | 61 | return createPortal( 62 | open ? ModalTemplate(omit) : null, 63 | document.body, 64 | ) 65 | } 66 | 67 | export default Modal 68 | -------------------------------------------------------------------------------- /electron-react/src/components/update/Modal/modal.module.scss: -------------------------------------------------------------------------------- 1 | .modal { 2 | --primary-color: rgb(224, 30, 90); 3 | 4 | :global { 5 | .modal-mask { 6 | width: 100vw; 7 | height: 100vh; 8 | position: fixed; 9 | left: 0; 10 | top: 0; 11 | z-index: 9; 12 | background: rgba(0, 0, 0, 0.45); 13 | } 14 | 15 | .modal-warp { 16 | position: fixed; 17 | top: 50%; 18 | left: 50%; 19 | transform: translate(-50%, -50%); 20 | z-index: 19; 21 | } 22 | 23 | .modal-content { 24 | box-shadow: 0 0 10px -4px rgb(130, 86, 208); 25 | overflow: hidden; 26 | border-radius: 4px; 27 | 28 | .modal-header { 29 | display: flex; 30 | line-height: 38px; 31 | background-color: var(--primary-color); 32 | 33 | .modal-header-text { 34 | font-weight: bold; 35 | width: 0; 36 | flex-grow: 1; 37 | } 38 | } 39 | 40 | .modal-close { 41 | width: 30px; 42 | height: 30px; 43 | margin: 4px; 44 | line-height: 34px; 45 | text-align: center; 46 | cursor: pointer; 47 | 48 | svg { 49 | width: 17px; 50 | height: 17px; 51 | } 52 | } 53 | 54 | .modal-body { 55 | padding: 10px; 56 | background-color: #fff; 57 | color: #333; 58 | } 59 | 60 | .modal-footer { 61 | padding: 10px; 62 | background-color: #fff; 63 | display: flex; 64 | justify-content: end; 65 | 66 | button { 67 | padding: 7px 11px; 68 | background-color: var(--primary-color); 69 | font-size: 14px; 70 | margin-left: 10px; 71 | 72 | &:first-child { 73 | margin-left: 0; 74 | } 75 | } 76 | } 77 | } 78 | 79 | .icon { 80 | padding: 0 15px; 81 | width: 20px; 82 | fill: currentColor; 83 | 84 | &:hover { 85 | color: rgba(0, 0, 0, 0.4); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /electron-react/src/components/update/Progress/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './progress.module.scss' 3 | 4 | const Progress: React.FC> = props => { 7 | const { percent = 0 } = props 8 | 9 | return ( 10 |
11 |
12 |
16 |
17 | {(percent ?? 0).toString().substring(0,4)}% 18 |
19 | ) 20 | } 21 | 22 | export default Progress 23 | -------------------------------------------------------------------------------- /electron-react/src/components/update/Progress/progress.module.scss: -------------------------------------------------------------------------------- 1 | .progress { 2 | display: flex; 3 | align-items: center; 4 | 5 | :global { 6 | .progress-pr { 7 | border: 1px solid #000; 8 | border-radius: 3px; 9 | height: 6px; 10 | width: 200px; 11 | } 12 | 13 | .progress-rate { 14 | height: 6px; 15 | border-radius: 3px; 16 | background-image: linear-gradient(to right, rgb(130, 86, 208) 0%, var(--primary-color) 100%) 17 | } 18 | 19 | .progress-num { 20 | margin: 0 10px; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /electron-react/src/components/update/electron-updater.d.ts: -------------------------------------------------------------------------------- 1 | interface VersionInfo { 2 | update: boolean 3 | version: string 4 | newVersion?: string 5 | } 6 | 7 | interface ErrorType { 8 | message: string 9 | error: Error 10 | } 11 | -------------------------------------------------------------------------------- /electron-react/src/components/update/index.tsx: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron' 2 | import type { ProgressInfo } from 'electron-updater' 3 | import { useCallback, useEffect, useState } from 'react' 4 | import Modal from '@/components/update/Modal' 5 | import Progress from '@/components/update/Progress' 6 | import styles from './update.module.scss' 7 | 8 | const Update = () => { 9 | const [checking, setChecking] = useState(false) 10 | const [updateAvailable, setUpdateAvailable] = useState(false) 11 | const [versionInfo, setVersionInfo] = useState() 12 | const [updateError, setUpdateError] = useState() 13 | const [progressInfo, setProgressInfo] = useState>() 14 | const [modalOpen, setModalOpen] = useState(false) 15 | const [modalBtn, setModalBtn] = useState<{ 16 | cancelText?: string 17 | okText?: string 18 | onCancel?: () => void 19 | onOk?: () => void 20 | }>({ 21 | onCancel: () => setModalOpen(false), 22 | onOk: () => ipcRenderer.invoke('start-download'), 23 | }) 24 | 25 | const checkUpdate = async () => { 26 | setChecking(true) 27 | /** 28 | * @type {import('electron-updater').UpdateCheckResult | null | { message: string, error: Error }} 29 | */ 30 | const result = await ipcRenderer.invoke('check-update') 31 | setProgressInfo({ percent: 0 }) 32 | setChecking(false) 33 | setModalOpen(true) 34 | if (result?.error) { 35 | setUpdateAvailable(false) 36 | setUpdateError(result?.error) 37 | } 38 | } 39 | 40 | const onUpdateCanAvailable = useCallback((_event: Electron.IpcRendererEvent, arg1: VersionInfo) => { 41 | setVersionInfo(arg1) 42 | setUpdateError(undefined) 43 | // Can be update 44 | if (arg1.update) { 45 | setModalBtn(state => ({ 46 | ...state, 47 | cancelText: 'Cancel', 48 | okText: 'Update', 49 | onOk: () => ipcRenderer.invoke('start-download'), 50 | })) 51 | setUpdateAvailable(true) 52 | } else { 53 | setUpdateAvailable(false) 54 | } 55 | }, []) 56 | 57 | const onUpdateError = useCallback((_event: Electron.IpcRendererEvent, arg1: ErrorType) => { 58 | setUpdateAvailable(false) 59 | setUpdateError(arg1) 60 | }, []) 61 | 62 | const onDownloadProgress = useCallback((_event: Electron.IpcRendererEvent, arg1: ProgressInfo) => { 63 | setProgressInfo(arg1) 64 | }, []) 65 | 66 | const onUpdateDownloaded = useCallback((_event: Electron.IpcRendererEvent, ...args: any[]) => { 67 | setProgressInfo({ percent: 100 }) 68 | setModalBtn(state => ({ 69 | ...state, 70 | cancelText: 'Later', 71 | okText: 'Install now', 72 | onOk: () => ipcRenderer.invoke('quit-and-install'), 73 | })) 74 | }, []) 75 | 76 | useEffect(() => { 77 | // Get version information and whether to update 78 | ipcRenderer.on('update-can-available', onUpdateCanAvailable) 79 | ipcRenderer.on('update-error', onUpdateError) 80 | ipcRenderer.on('download-progress', onDownloadProgress) 81 | ipcRenderer.on('update-downloaded', onUpdateDownloaded) 82 | 83 | return () => { 84 | ipcRenderer.off('update-can-available', onUpdateCanAvailable) 85 | ipcRenderer.off('update-error', onUpdateError) 86 | ipcRenderer.off('download-progress', onDownloadProgress) 87 | ipcRenderer.off('update-downloaded', onUpdateDownloaded) 88 | } 89 | }, []) 90 | 91 | return ( 92 | <> 93 | 101 |
102 | {updateError 103 | ? ( 104 |
105 |

Error downloading the latest version.

106 |

{updateError.message}

107 |
108 | ) : updateAvailable 109 | ? ( 110 |
111 |
The last version is: v{versionInfo?.newVersion}
112 |
v{versionInfo?.version} -> v{versionInfo?.newVersion}
113 |
114 |
Update progress:
115 |
116 | 117 |
118 |
119 |
120 | ) 121 | : ( 122 |
{JSON.stringify(versionInfo ?? {}, null, 2)}
123 | )} 124 |
125 |
126 | 129 | 130 | ) 131 | } 132 | 133 | export default Update 134 | -------------------------------------------------------------------------------- /electron-react/src/components/update/update.module.scss: -------------------------------------------------------------------------------- 1 | .modalslot { 2 | // display: flex; 3 | // align-items: center; 4 | // justify-content: center; 5 | 6 | :global { 7 | .update-progress { 8 | display: flex; 9 | } 10 | 11 | .progress-title { 12 | margin-right: 10px; 13 | } 14 | 15 | .progress-bar { 16 | width: 0; 17 | flex-grow: 1; 18 | } 19 | 20 | .can-available { 21 | .new-version-target,.update-progress { 22 | margin-left: 40px; 23 | } 24 | } 25 | 26 | .can-not-available { 27 | padding: 20px; 28 | text-align: center; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /electron-react/src/data/data.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/AthenaJS/1323799913405bc6c8511a681f84dcf3ec10c854/electron-react/src/data/data.json -------------------------------------------------------------------------------- /electron-react/src/hooks/useContextHooks.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { UserCompContext } from '../components/context/UserCompContext'; 3 | import { PerformanceContext } from '../components/context/PerformanceContext'; 4 | import { MockFetchContext } from '../components/context/MockFetchContext'; 5 | import { DetailsContext } from '../components/context/DetailsContext'; 6 | import { ShowUIContext } from '../components/context/ShowUIContext'; 7 | 8 | // custom hook to perform runtime check on PerformanceContext output 9 | // these have to be separate error checks for each context for typescript runtime checking 10 | export const useUserComp = () => { 11 | const context = useContext(UserCompContext); 12 | 13 | if (!context) { 14 | throw Error(`UserCompContext must be used inside a UserCompContext.Provider`); 15 | } 16 | 17 | return context; 18 | }; 19 | 20 | export const usePerformance = () => { 21 | const context = useContext(PerformanceContext); 22 | 23 | if (!context) { 24 | throw Error(`PerformanceContext must be used inside a PerformanceContext.Provider`); 25 | } 26 | 27 | return context; 28 | }; 29 | 30 | export const useMockFetch = () => { 31 | const context = useContext(MockFetchContext); 32 | 33 | if (!context) { 34 | throw Error(`MockFetchContext must be used inside a MockFetchContext.Provider`); 35 | } 36 | 37 | return context; 38 | }; 39 | 40 | export const useDetails = () => { 41 | const context = useContext(DetailsContext); 42 | 43 | if (!context) { 44 | throw Error(`DetailsContext must be used inside a DetailsContext.Provider`); 45 | } 46 | 47 | return context; 48 | }; 49 | 50 | export const useShowUI = () => { 51 | const context = useContext(ShowUIContext); 52 | 53 | if (!context) { 54 | throw Error(`ShowUIContext must be used inside a ShowUIContext.Provider`); 55 | } 56 | 57 | return context; 58 | }; 59 | -------------------------------------------------------------------------------- /electron-react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './samples/node-api' 5 | import { UserCompProvider } from './components/context/UserCompContext' 6 | import { DetailsProvider } from './components/context/DetailsContext'; 7 | import { PerformanceProvider } from './components/context/PerformanceContext'; 8 | import { MockFetchProvider } from './components/context/MockFetchContext'; 9 | import { ShowUIProvider } from './components/context/ShowUIContext' 10 | import {AnimatePresence} from 'framer-motion'; 11 | 12 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | , 28 | ) 29 | 30 | postMessage({ payload: 'removeLoading' }, '*') 31 | -------------------------------------------------------------------------------- /electron-react/src/pages/UIPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import ViewUI from '../components/UIWindow/ViewUI'; 3 | import AthenaLogoSvg from '../components/framerMotion/AthenaLogo'; 4 | 5 | const UIPage = () => { 6 | return( 7 |
8 | 9 | 10 |
11 | ); 12 | 13 | }; 14 | 15 | export default UIPage; -------------------------------------------------------------------------------- /electron-react/src/pages/Workshop.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import NavigationContainer from '@/components/Navigation/NavigationContainer'; 3 | import ViewComponent from '@/components/WorkshopMain/ViewComponent'; 4 | import { Resizable } from 're-resizable'; 5 | 6 | const Workshop = () => { 7 | return( 8 |
9 | 10 | 29 | 30 | 31 |
32 | ); 33 | 34 | }; 35 | 36 | export default Workshop; -------------------------------------------------------------------------------- /electron-react/src/samples/node-api.ts: -------------------------------------------------------------------------------- 1 | import { lstat } from 'node:fs/promises' 2 | import { cwd } from 'node:process' 3 | import { ipcRenderer } from 'electron' 4 | 5 | ipcRenderer.on('main-process-message', (_event, ...args) => { 6 | console.log('[Receive Main-process message]:', ...args) 7 | }) 8 | 9 | lstat(cwd()).then(stats => { 10 | console.log('[fs.lstat]', stats) 11 | }).catch(err => { 12 | console.error(err) 13 | }) 14 | -------------------------------------------------------------------------------- /electron-react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /electron-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "noImplicitAny": true, 5 | "useDefineForClassFields": true, 6 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 7 | "allowJs": true, 8 | "skipLibCheck": true, 9 | "esModuleInterop": false, 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "module": "ESNext", 14 | "moduleResolution": "Node", 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx", 19 | "baseUrl": "./", 20 | "paths": { 21 | "@/*": [ 22 | "src/*" 23 | ] 24 | }, 25 | }, 26 | "include": ["src"], 27 | "references": [{ "path": "./tsconfig.node.json" }] 28 | } 29 | -------------------------------------------------------------------------------- /electron-react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "resolveJsonModule": true, 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts", "package.json", "electron"] 10 | } 11 | -------------------------------------------------------------------------------- /electron-react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { rmSync } from 'node:fs' 2 | import path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import react from '@vitejs/plugin-react' 5 | import electron from 'vite-electron-plugin' 6 | import { customStart, loadViteEnv } from 'vite-electron-plugin/plugin' 7 | import renderer from 'vite-plugin-electron-renderer' 8 | import pkg from './package.json' 9 | 10 | // https://vitejs.dev/config/ 11 | export default defineConfig(({ command }) => { 12 | rmSync('dist-electron', { recursive: true, force: true }) 13 | 14 | const sourcemap = command === 'serve' || !!process.env.VSCODE_DEBUG 15 | 16 | return { 17 | resolve: { 18 | alias: { 19 | '@': path.join(__dirname, 'src'), 20 | 'react-dom/client': path.resolve( 21 | __dirname, 22 | 'node_modules/react-dom/profiling.js' 23 | ), 24 | 'scheduler/tracing': path.resolve( 25 | __dirname, 26 | 'node_modules/scheduler/tracing-profiling' 27 | ), 28 | }, 29 | }, 30 | plugins: [ 31 | react(), 32 | electron({ 33 | include: [ 34 | 'electron' 35 | ], 36 | transformOptions: { 37 | sourcemap, 38 | }, 39 | plugins: [ 40 | ...(!!process.env.VSCODE_DEBUG 41 | ? [ 42 | // Will start Electron via VSCode Debug 43 | customStart(() => console.log(/* For `.vscode/.debug.script.mjs` */'[startup] Electron App')), 44 | ] 45 | : []), 46 | // Allow use `import.meta.env.VITE_SOME_KEY` in Electron-Main 47 | loadViteEnv(), 48 | ], 49 | }), 50 | // Use Node.js API in the Renderer-process 51 | renderer({ 52 | nodeIntegration: true, 53 | }), 54 | ], 55 | server: !!process.env.VSCODE_DEBUG ? (() => { 56 | const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL) 57 | return { 58 | host: url.hostname, 59 | port: +url.port, 60 | } 61 | })() : undefined, 62 | clearScreen: false, 63 | } 64 | }) 65 | -------------------------------------------------------------------------------- /electron-react/vite.legacy.config.ts: -------------------------------------------------------------------------------- 1 | import { rmSync } from 'node:fs' 2 | import path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import react from '@vitejs/plugin-react' 5 | import electron from 'vite-electron-plugin' 6 | import { customStart, loadViteEnv } from 'vite-electron-plugin/plugin' 7 | import preload from 'vite-plugin-electron' 8 | import renderer from 'vite-plugin-electron-renderer' 9 | import pkg from './package.json' 10 | 11 | let preloadHasReady = false 12 | 13 | // https://vitejs.dev/config/ 14 | export default defineConfig(({ command }) => { 15 | rmSync('dist-electron', { recursive: true, force: true }) 16 | 17 | const sourcemap = command === 'serve' || !!process.env.VSCODE_DEBUG 18 | 19 | return { 20 | resolve: { 21 | alias: { 22 | '@': path.join(__dirname, 'src'), 23 | 'react-dom/client': path.resolve( 24 | __dirname, 25 | 'node_modules/react-dom/profiling.js' 26 | ), 27 | 'scheduler/tracing': path.resolve( 28 | __dirname, 29 | 'node_modules/scheduler/tracing-profiling' 30 | ), 31 | }, 32 | }, 33 | plugins: [ 34 | react(), 35 | electron({ 36 | include: [ 37 | 'electron/main' 38 | ], 39 | transformOptions: { 40 | sourcemap, 41 | }, 42 | plugins: [ 43 | customStart(args => { 44 | if (process.env.VSCODE_DEBUG) { 45 | // Start Electron via VSCode 46 | console.log(/* For `.vscode/.debug.script.mjs` */'[startup] Electron App') 47 | } else { 48 | if (preloadHasReady) { 49 | args?.startup() 50 | } else { 51 | console.log('[startup] waiting for preload') 52 | } 53 | } 54 | }), 55 | // Allow use `import.meta.env.VITE_SOME_KEY` in Main process 56 | loadViteEnv(), 57 | ], 58 | }), 59 | // Preload scripts 60 | preload({ 61 | entry: [ 62 | 'electron/preload/index.ts' 63 | ], 64 | vite: { 65 | build: { 66 | minify: false, 67 | outDir: 'dist-electron/preload', 68 | }, 69 | }, 70 | onstart(args) { 71 | if (preloadHasReady) { 72 | args.reload() 73 | } else { 74 | preloadHasReady = true 75 | args.startup() 76 | } 77 | }, 78 | }), 79 | // Use Node.js API in the Renderer process 80 | renderer({ 81 | nodeIntegration: true, 82 | }), 83 | ], 84 | server: !!process.env.VSCODE_DEBUG ? (() => { 85 | const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL) 86 | return { 87 | host: url.hostname, 88 | port: +url.port, 89 | } 90 | })() : undefined, 91 | clearScreen: false, 92 | } 93 | }) 94 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Athena", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": {} 6 | } --------------------------------------------------------------------------------