diff --git a/README.md b/README.md deleted file mode 100644 index f5439dc02e78533095f164f1320fb2d52c95d730..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,183 +0,0 @@ -# React Redux Starter Code - -A minimal app to be used as starter code for labs and homework in the SOFT 260 -course at UNL. The starter code demonstrates basic usage of the React Hooks -API, the Redux Toolkit (RTK), React Router, Jest, and the React Testing Library -(RTL) in the context of a React Redux progressive web app (PWA). - -# Quick Start - -Recursively clone this repository and `cd` into the root folder: - -```bash -$ git clone --recursive git@git.unl.edu:soft-core/soft-260/react-redux-starter-code.git -$ cd react-redux-starter-code -``` - -(If you forget `--recursive` when cloning, you can `cd` into your clone and run -`git submodule update --init --recursive` instead.) - -Install dependencies: - -```bash -$ npm install -``` - -(You may see a few warnings because `create-react-app` transitively depends on -some deprecated packages.) - -Optionally run the linter and the test suite: - -``` -$ npm run lint -$ npm run test -``` - -And then serve the application locally: - -``` -$ npm start -``` - -When you are done, press control-c to stop the server. - -# Folders and Files - -The folders and files in the starter code are briefly described below. React -Redux applications use a model-view-controller (MVC) architecture (see -<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>), so in -these descriptions the terms "model", "view", and "controller" refer to those -roles from MVC. - -## Submodules - -* The Git submodule `stylelint-config` contains the stylelint configuration - for the coding style used in the `minimal-app` project. - -* The Git submodule `eslint-config` contains the ESLint configuration for the - coding style used in the `minimal-app` project. Per `create-react-app` - convention, in a development build of the main app, a separate, weaker - coding style also warns at runtime about likely bugs. - -## General Configuration - -* The file `minimal-app/.gitignore` prevents non-source-code files from being - accidentally committed to the repository. - -* The file `minimal-app/package.json` describes the project and its - dependencies. It can be edited to customize the inputs and processes used - in various software lifecyle tasks like linting, testing, or deploying. - -* The file `minimal-app/package-lock.json` records the exact set of - dependencies used to satisfy the requirements in `minimal-app/package.json`. - It should not be hand-edited; use commands like `npm install` or `npm - uninstall` from the `minimal-app` directory to make changes. - -* The folder `minimal-app/node_modules` contains the dependencies installed by - `npm`. - -## Application Infrastructure - -* The file `minimal-app/public/manifest.json` provides data needed to run the - web application as a PWA. (See - <https://developer.mozilla.org/en-US/docs/Web/Manifest> for more - information.) - -* The file `minimal-app/public/logo.svg` is the image used for the app's icon. - (A maskable icon is recommended; see <https://web.dev/maskable-icon/> for - more information and <https://maskable.app/> to test an image.) - -* The file `minimal-app/public/index.html` contains the skeleton document in - which the app's HTML is embedded. - -* The file `minimal-app/src/index.js` specifies other wrappers around the - application proper than cannot be given in `index.html`, usually because - they involve React components, not pure HTML. In this case, the wrappers: - - * Enable extra checks at development time using React strict mode. (See - <https://reactjs.org/docs/strict-mode.html> for more information.) - - * Make the Redux store from `minimal-app/src/app/store.js` available to - the app's React components. - - * Enable routing with React Router. (See - <https://reacttraining.com/react-router/web> for more information.) - - * Apply the letterboxed portrait layout from `index.css`, which is - described next. - -* The file `minimal-app/src/index.css` contains the CSS associated with - `index.html`. In this case the CSS forces a letterboxed portrait layout and - specifies a sans-serif font. - -## Model and Controller Code - -* The file `minimal-app/src/app/store.js` combines the models provided by the - app's features to create a model for the whole app. - -* The file `minimal-app/src/features/counter/counterSlice.js` implements a - Redux slice, the model and associated controllers for a particular feature, - which in this case is a simple counter. (See - <https://redux-toolkit.js.org/> for more information.) - -## View Code - -* The file `minimal-app/src/app.js` implements the React component - representing the entire app. In this case only the universal route, `/*`, - is implemented, but the returned fragment is intentionally written so that - it is easy to add additional routes. - -* The file `minimal-app/src/features/counter/counter.js` implements a React - component that counts the number of times a user has tapped a button. This - component uses the slice from `counterSlice.js`. - -* The file `minimal-app/src/features/counter/counter.module.css` provides - styles for the React component in `counter.js`. - -## Test Infrastructure - -* The file `minimal-app/src/setupTests.js` provides setup code that applies to - every test case. In this case that code imports RTL's custom matchers from - testing React components. - -* The file `minimal-app/src/testing/mockRedux.js` provides the ability to mock - the part of Redux used by React components under the React Hooks API so that - those view components can be tested independently of model and controller - code. - -## Test Code - -* The file `minimal-app/app.test.js` demonstrates a snapshot regression test - of the app component with mocked selectors. (See - <https://jestjs.io/docs/en/snapshot-testing> for more information.) - -* The file `minimal-app/src/__snapshots__/app.test.js.snap` contains the - oracles for the snapshot tests in `app.test.js`. When the tests are run in - watch mode (using the command `npm test`), these oracles can be updated - interactively if a snapshot test fails due to changed requirements. - -* The file `minimal-app/src/features/counter/counter.test.js` demonstrates - non-snapshot tests of the view code in the counter component. - -* The file `minimal-app/src/features/counter/counterSlice.test.js` - demonstrates tests of model and controller code. - -# Adaptation Checklist - -When adapting this code for a new project, make sure to do at least the -following: - -* Change the project name, version number, and description in - `minimal-app/package.json`. - -* Change the short name, name, description, colors, and other settings in - `minimal-app/public/manifest.json`. - -* Change the title, description, and theme color in - `minimal-app/public/index.html`. - -* Rename the folder from `minimal-app` to something descriptive and change the - corresponding entries in the outer `package.json`. - -* Rerun `npm install` in the outer folder to update `package-lock.json` based - on the above changes. diff --git a/minimal-app/.gitignore b/algorithm-explorer/.gitignore similarity index 100% rename from minimal-app/.gitignore rename to algorithm-explorer/.gitignore diff --git a/minimal-app/package-lock.json b/algorithm-explorer/package-lock.json similarity index 99% rename from minimal-app/package-lock.json rename to algorithm-explorer/package-lock.json index 9d4e5d41f2c165d88b55e61e3df526fede061b74..4a2c45271d0e00460b3ac335c4627da40bfa74d9 100644 --- a/minimal-app/package-lock.json +++ b/algorithm-explorer/package-lock.json @@ -1,12 +1,12 @@ { - "name": "@unlsoft/minimal-app", - "version": "1.0.0", + "name": "@unlsoft/algorithm-explorer", + "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "@unlsoft/minimal-app", - "version": "1.0.0", + "name": "@unlsoft/algorithm-explorer", + "version": "0.0.1", "license": "UNLICENSED", "dependencies": { "@reduxjs/toolkit": "^1.8.3", diff --git a/minimal-app/package.json b/algorithm-explorer/package.json similarity index 94% rename from minimal-app/package.json rename to algorithm-explorer/package.json index e726731eb68a128fd9f540f700730591c8954892..2c8a0803aca6453ff812c9b2bdcfc2587673d94a 100644 --- a/minimal-app/package.json +++ b/algorithm-explorer/package.json @@ -1,7 +1,7 @@ { - "name": "@unlsoft/minimal-app", - "version": "1.0.0", - "description": "A minimal app to be used as starter code for labs and homework.", + "name": "@unlsoft/algorithm-explorer", + "version": "0.0.1", + "description": "An designed to help learn the difference in algorithms", "private": true, "license": "UNLICENSED", "scripts": { diff --git a/algorithm-explorer/public/index.html b/algorithm-explorer/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..b7d1bde7dda23ad9b365e88c0e7cee0fad1de931 --- /dev/null +++ b/algorithm-explorer/public/index.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Algorithm Explorer</title> +</head> +<body> + <div id="root"></div> + <script src="./bundle.js"></script> +</body> +</html> diff --git a/algorithm-explorer/public/logo.png b/algorithm-explorer/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aeef41a960da0d9c6dbcdf0e2f0238e9c332e3e5 Binary files /dev/null and b/algorithm-explorer/public/logo.png differ diff --git a/minimal-app/public/logo.svg b/algorithm-explorer/public/logo.svg similarity index 100% rename from minimal-app/public/logo.svg rename to algorithm-explorer/public/logo.svg diff --git a/minimal-app/public/manifest.json b/algorithm-explorer/public/manifest.json similarity index 73% rename from minimal-app/public/manifest.json rename to algorithm-explorer/public/manifest.json index 31d7bfd948705adf2fb8e85572e3519b98eae7b5..81f44f021cb4c9110fc38b700dc96d0f425ce3d3 100644 --- a/minimal-app/public/manifest.json +++ b/algorithm-explorer/public/manifest.json @@ -1,7 +1,7 @@ { - "short_name": "Minimal App", - "name": "Minimal React Redux App", - "description": "A minimal app to be used as starter code for labs and homework.", + "short_name": "Algorithm Explorer", + "name": "Algorithm Explorer App", + "description": "An app to help with the understanding of algorithms.", "icons": [ { "src": "logo.svg", diff --git a/algorithm-explorer/src/app.js b/algorithm-explorer/src/app.js new file mode 100644 index 0000000000000000000000000000000000000000..c590865e4fbc4f33ffd8758fd9b604bffac624d1 --- /dev/null +++ b/algorithm-explorer/src/app.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import AlgorithmSelection from './components/AlgorithmSelection'; +import BFS from './components/BFS'; +import DFS from './components/DFS'; +import Dijkstra from './components/Dijkstra'; +import GreedyAlgorithm from './components/GreedyAlgorithm'; +import DAC from './components/DAC'; + +const App = () => + <Router> + <Routes> + {/* Default route: AlgorithmSelection */} + <Route path="/algorithm-selection" element={<AlgorithmSelection />} /> + {/* Routes for individual algorithms */} + <Route path="/bfs" element={<BFS />} /> + <Route path="/dfs" element={<DFS />} /> + <Route path="/dijkstra" element={<Dijkstra />} /> + <Route path="/greedy-algorithm" element={<GreedyAlgorithm />} /> + <Route path="/dac" element={<DAC />} /> + </Routes> + </Router> +; + +export default App; diff --git a/algorithm-explorer/src/components/AlgorithmSelection.css b/algorithm-explorer/src/components/AlgorithmSelection.css new file mode 100644 index 0000000000000000000000000000000000000000..94e9b6773fd6d738d035269d6fd8834b4cee22ba --- /dev/null +++ b/algorithm-explorer/src/components/AlgorithmSelection.css @@ -0,0 +1,45 @@ +.algorithm-selection { + text-align: center; + margin-top: 50px; + color: rgb(218 218 218); +} + +.algorithm-list { + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 20px; + margin-top: 20px; +} + +.algorithm-link { + text-decoration: none; +} + +.algorithm-card { + width: 200px; + height: 100px; + background-color: rgb(240 240 240); + display: flex; + justify-content: center; + align-items: center; + border: 2px solid rgb(218 218 218); + border-radius: 8px; + font-size: 18px; + font-weight: bold; + color: rgb(51 51 51); + transition: 0.3s ease-in-out; + text-align: center; + box-shadow: 0 4px 6px rgba(0 0 0 10%); +} + +.algorithm-card:hover { + background-color: rgb(224 224 224); + transform: scale(1.05); + cursor: pointer; +} + +.algorithm-card a { + text-decoration: none; + color: inherit; +} diff --git a/algorithm-explorer/src/components/AlgorithmSelection.jsx b/algorithm-explorer/src/components/AlgorithmSelection.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c0b4a5ebe9cd4c8262e8c642cdc6c32db6168bde --- /dev/null +++ b/algorithm-explorer/src/components/AlgorithmSelection.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import './AlgorithmSelection.css'; + +const AlgorithmSelection = () => + <div className="algorithm-selection"> + <h1>Select an Algorithm to Explore</h1> + <div className="algorithm-list"> + <Link to="/bfs" className="algorithm-link"> + <div className="algorithm-card">Breadth-First Search (BFS)</div> + </Link> + <Link to="/dfs" className="algorithm-link"> + <div className="algorithm-card">Depth-First Search (DFS)</div> + </Link> + <Link to="/dijkstra" className="algorithm-link"> + <div className="algorithm-card">Dijkstra's Algorithm</div> + </Link> + <Link to="/greedy-algorithm" className="algorithm-link"> + <div className="algorithm-card">Greedy Algorithm</div> + </Link> + <Link to="/dac" className="algorithm-link"> + <div className="algorithm-card">Divide and Conquer</div> + </Link> + </div> + </div> +; + +export default AlgorithmSelection; diff --git a/algorithm-explorer/src/components/BFS.jsx b/algorithm-explorer/src/components/BFS.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a053d74605f6abc5007a7626965e484039fd91cc --- /dev/null +++ b/algorithm-explorer/src/components/BFS.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const BFS = () => + <div> + <h1>Breadth-First Search (BFS)</h1> + <p>This is where you can visualize the BFS algorithm.</p> + {/* Add your graph visualizer or algorithm logic here */} + </div> + ; + +export default BFS; diff --git a/algorithm-explorer/src/components/DAC.jsx b/algorithm-explorer/src/components/DAC.jsx new file mode 100644 index 0000000000000000000000000000000000000000..7b1cb4e282ce16abb6a84c5f2af3285344c10b3b --- /dev/null +++ b/algorithm-explorer/src/components/DAC.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const DAC = () => + <div> + <h1>Divide and Conquer Algorithm</h1> + <p>This is where you can visualize Divide and Conquer algorithm.</p> + {/* Add your graph visualizer or algorithm logic here */} + </div> + ; + +export default DAC; diff --git a/algorithm-explorer/src/components/DFS.jsx b/algorithm-explorer/src/components/DFS.jsx new file mode 100644 index 0000000000000000000000000000000000000000..e8abc06ecea70d1317873805f9e2ed843c2366cd --- /dev/null +++ b/algorithm-explorer/src/components/DFS.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const DFS = () => + <div> + <h1>Depth-First Search (DFS)</h1> + <p>This is where you can visualize the DFS algorithm.</p> + {/* Add your graph visualizer or algorithm logic here */} + </div> + ; + +export default DFS; diff --git a/algorithm-explorer/src/components/Dijkstra.jsx b/algorithm-explorer/src/components/Dijkstra.jsx new file mode 100644 index 0000000000000000000000000000000000000000..14693851f81859ca9c8366892ef9c0c7c066c1b5 --- /dev/null +++ b/algorithm-explorer/src/components/Dijkstra.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const Dijkstra = () => + <div> + <h1>Dijkstra's Algorithm</h1> + <p>This is where you can visualize Dijkstra's algorithm.</p> + {/* Add your graph visualizer or algorithm logic here */} + </div> + ; + +export default Dijkstra; diff --git a/algorithm-explorer/src/components/GreedyAlgorithm.jsx b/algorithm-explorer/src/components/GreedyAlgorithm.jsx new file mode 100644 index 0000000000000000000000000000000000000000..989b92b471d1f38054df76b73a14eac581eb4b40 --- /dev/null +++ b/algorithm-explorer/src/components/GreedyAlgorithm.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const GreedyAlgorithm = () => + <div> + <h1>Greedy Algorithm</h1> + <p>This is where you can visualize Greedy algorithm.</p> + {/* Add your graph visualizer or algorithm logic here */} + </div> + ; + +export default GreedyAlgorithm; diff --git a/algorithm-explorer/src/components/LandingPage.css b/algorithm-explorer/src/components/LandingPage.css new file mode 100644 index 0000000000000000000000000000000000000000..068c6da20e729113f14be1682704d46374179ec9 --- /dev/null +++ b/algorithm-explorer/src/components/LandingPage.css @@ -0,0 +1,73 @@ +:root { + /* Colors */ + --letterbox-color: rgba(0 0 0 / 100%); + --app-background-color: rgba(239 239 239 / 100%); + --font-color: rgba(255 255 255 / 100%); + --highlight-color: rgba(115 168 254 / 100%); + --button-background-color: rgb(0 98 255); + --button-hover-color: rgb(0 86 230); + + /* Sizes */ + --minimum-app-size: 300px; +} + +body { + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: rgb(125 125 125); +} + +.landing-page { + display: flex; + align-items: center; /* Center logo and text vertically */ + justify-content: space-between; /* Push logo and text apart */ + width: 90%; + max-width: 1200px; + height: auto; + background-color: transparent; /* Remove any background */ +} + +.image-container { + flex-shrink: 0; /* Prevent shrinking of the logo */ + max-width: 40%; /* Limit the width of the logo */ + text-align: left; +} + +.image-container img { + max-width: 100%; /* Ensure the image fits within the container */ + height: auto; + display: block; + border: none; /* Remove any borders from the image */ +} + +.content { + flex-grow: 1; /* Allow the text container to grow */ + margin-left: 20px; /* Add spacing between the logo and text */ + text-align: left; +} + +.content h1 { + font-size: 48px; + margin-bottom: 20px; + color: var(--highlight-color); /* Highlight color for the title */ +} + +.start-button { + padding: 15px 30px; + font-size: 20px; + background-color: var(--button-background-color); /* Button background color */ + color: var(--font-color); /* Button font color */ + border: none; + border-radius: 5px; + cursor: pointer; + text-decoration: none; + transition: background-color 0.3s ease; +} + +.start-button:hover { + background-color: var(--button-hover-color); /* Hover effect for button */ +} diff --git a/algorithm-explorer/src/components/LandingPage.jsx b/algorithm-explorer/src/components/LandingPage.jsx new file mode 100644 index 0000000000000000000000000000000000000000..efb89034dd63425f383caa9889ca2a74e21dfc3f --- /dev/null +++ b/algorithm-explorer/src/components/LandingPage.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import './LandingPage.css'; + +const LandingPage = () => { + const navigate = useNavigate(); + + const handleStart = () => { + navigate('/algorithm-selection'); + }; + + return ( + <div className="landing-page"> + <div className="image-container"> + <img src="logo.png" alt="Algorithm Explorer Logo" /> + </div> + <div className="content"> + <h1>Welcome to Algorithm Explorer</h1> + <button onClick={handleStart} className="start-button">Start</button> + </div> + </div> + ); +}; + +export default LandingPage; diff --git a/algorithm-explorer/src/index.css b/algorithm-explorer/src/index.css new file mode 100644 index 0000000000000000000000000000000000000000..1e7eb464b844a1d953ed53503322d541b13ddf66 --- /dev/null +++ b/algorithm-explorer/src/index.css @@ -0,0 +1,73 @@ +:root { + /* Colors */ + --letterbox-color: rgba(0 0 0 / 100%); + --app-background-color: rgba(239 239 239 / 100%); + --font-color: rgba(255 255 255 / 100%); + --highlight-color: rgba(115 168 254 / 100%); + --button-background-color: rgb(0 98 255); + --button-hover-color: rgb(0 86 230); + + /* Sizes */ + --minimum-app-size: 300px; +} + +body { + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: rgb(125 125 125); +} + +.landing-page { + display: flex; + align-items: center; /* Center logo and text vertically */ + justify-content: space-between; /* Push logo and text apart */ + width: 90%; + max-width: 1200px; + height: auto; + background-color: transparent; /* Remove any background */ +} + +.image-container { + flex-shrink: 0; /* Prevent shrinking of the logo */ + max-width: 40%; /* Limit the width of the logo */ + text-align: left; +} + +.image-container img { + max-width: 100%; /* Ensure the image fits within the container */ + height: auto; + display: block; + border: none; /* Remove any borders from the image */ +} + +.content { + flex-grow: 1; /* Allow the text container to grow */ + margin-left: 20px; /* Add spacing between the logo and text */ + text-align: left; +} + +.content h1 { + font-size: 48px; + margin-bottom: 20px; + color: var(--highlight-color); /* Highlight color for the title */ +} + +.start-button { + padding: 15px 30px; + font-size: 20px; + background-color: var(--button-background-color); + color: var(--font-color); + border: none; + border-radius: 5px; + cursor: pointer; + text-decoration: none; + transition: background-color 0.3s ease; +} + +.start-button:hover { + background-color: var(--button-hover-color); +} diff --git a/algorithm-explorer/src/index.js b/algorithm-explorer/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a2e2abc7a21aa058c6791403537428447421cb26 --- /dev/null +++ b/algorithm-explorer/src/index.js @@ -0,0 +1,33 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { Provider } from 'react-redux'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; + +import store from './store'; +import './index.css'; +import AlgorithmSelection from './components/AlgorithmSelection.jsx'; +import BFS from './components/BFS.jsx'; +import DFS from './components/DFS.jsx'; +import Dijkstra from './components/Dijkstra.jsx'; +import GreedyAlgorithm from './components/GreedyAlgorithm'; +import DAC from './components/DAC'; +import LandingPage from './components/LandingPage.jsx'; + +createRoot(document.getElementById('root')).render( + <React.StrictMode> + <Provider store={store}> + <Router> + <Routes> + {/* Algorithm Selection is the default ("/") route */} + <Route path="/" element={<LandingPage />} /> + <Route path="/algorithm-selection" element={<AlgorithmSelection />} /> + <Route path="/bfs" element={<BFS />} /> + <Route path="/dfs" element={<DFS />} /> + <Route path="/dijkstra" element={<Dijkstra />} /> + <Route path="/greedy-algorithm" element={<GreedyAlgorithm />} /> + <Route path="/dac" element={<DAC />} /> + </Routes> + </Router> + </Provider> + </React.StrictMode>, +); diff --git a/algorithm-explorer/src/store.js b/algorithm-explorer/src/store.js new file mode 100644 index 0000000000000000000000000000000000000000..4a487da08361af1e0f68d75d6a34e5526663a184 --- /dev/null +++ b/algorithm-explorer/src/store.js @@ -0,0 +1,9 @@ +import { configureStore } from '@reduxjs/toolkit'; + +const reducer = {}; + +const store = configureStore({ + reducer, +}); + +export default store; diff --git a/minimal-app/public/index.html b/minimal-app/public/index.html deleted file mode 100644 index 334b00e880936e215c05ff5438593f31e66267a3..0000000000000000000000000000000000000000 --- a/minimal-app/public/index.html +++ /dev/null @@ -1,24 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1" /> - <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> - <meta - name="description" - content="A minimal app to be used as starter code for labs and homework." - /> - <meta name="theme-color" content="#d00000" /> - <link rel="icon" href="%PUBLIC_URL%/logo.png" /> - <link rel="icon" href="%PUBLIC_URL%/logo.svg" /> - <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" /> - <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.svg" /> - <link rel="apple-touch-startup-image" href="%PUBLIC_URL%/logo.png" /> - <link rel="apple-touch-startup-image" href="%PUBLIC_URL%/logo.svg" /> - <title>Minimal React Redux App</title> - </head> - <body> - <noscript>You need to enable JavaScript to run this app.</noscript> - <div id="root"></div> - </body> -</html> diff --git a/minimal-app/public/logo.png b/minimal-app/public/logo.png deleted file mode 100644 index 8fdf4626ff909640cbb6fdd996565794bf42a43e..0000000000000000000000000000000000000000 Binary files a/minimal-app/public/logo.png and /dev/null differ diff --git a/minimal-app/src/__snapshots__/app.test.js.snap b/minimal-app/src/__snapshots__/app.test.js.snap deleted file mode 100644 index ce50593a1264fefe9e1e6f5b2728f70ba16a88e5..0000000000000000000000000000000000000000 --- a/minimal-app/src/__snapshots__/app.test.js.snap +++ /dev/null @@ -1,15 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`the app has one labeled button that displays the value from the store 1`] = ` -<div> - <label> - Taps - : - <button - class="blue" - > - 9999 - </button> - </label> -</div> -`; diff --git a/minimal-app/src/app.js b/minimal-app/src/app.js deleted file mode 100644 index e875b5f1efaa2f9d67b50f129e9b056491157407..0000000000000000000000000000000000000000 --- a/minimal-app/src/app.js +++ /dev/null @@ -1,15 +0,0 @@ -import { Routes, Route } from 'react-router-dom'; - -import { Counter } from './features/counter/counter.js'; - -export function App() { - const page = - <> - <Counter label={'Taps'} /> - </>; - return ( - <Routes> - <Route path={'/*'} element={page} /> - </Routes> - ); -} diff --git a/minimal-app/src/app.test.js b/minimal-app/src/app.test.js deleted file mode 100644 index cea18d811df2753271a4762fa0c1dfe567ae5755..0000000000000000000000000000000000000000 --- a/minimal-app/src/app.test.js +++ /dev/null @@ -1,24 +0,0 @@ -import { render } from '@testing-library/react'; -import './testing/mockRedux.js'; -import { MemoryRouter as Router } from 'react-router-dom'; - -import { App } from './app.js'; - -import { - selectValue, -} from './features/counter/counterSlice.js'; -jest.mock('./features/counter/counterSlice.js', () => ({ - selectValue: jest.fn().mockName('selectValue'), -})); - -describe('the app', () => { - test('has one labeled button that displays the value from the store', () => { - selectValue.mockReturnValue(9999); - const { container } = render( - <Router initialEntries={['/']}> - <App /> - </Router>, - ); - expect(container).toMatchSnapshot(); - }); -}); diff --git a/minimal-app/src/app/store.js b/minimal-app/src/app/store.js deleted file mode 100644 index ff522e191c94a67fbc4f4aa5164fcd9fb6511ca9..0000000000000000000000000000000000000000 --- a/minimal-app/src/app/store.js +++ /dev/null @@ -1,9 +0,0 @@ -import { configureStore } from '@reduxjs/toolkit'; - -import counterSlice from '../features/counter/counterSlice.js'; - -export const store = configureStore({ - reducer: { - [counterSlice.name]: counterSlice.reducer, - }, -}); diff --git a/minimal-app/src/features/counter/counter.js b/minimal-app/src/features/counter/counter.js deleted file mode 100644 index a09d3e487b6e5f738d16b32c4babedebd3181db4..0000000000000000000000000000000000000000 --- a/minimal-app/src/features/counter/counter.js +++ /dev/null @@ -1,36 +0,0 @@ -import { useSelector, useDispatch } from 'react-redux'; -import PropTypes from 'prop-types'; - -import classNames from 'classnames'; -import styles from './counter.module.css'; - -import { - selectValue, - setValue, -} from './counterSlice.js'; - -export function Counter(props) { - const value = useSelector(selectValue); - const dispatch = useDispatch(); - - const classes = classNames({ - [styles.red]: value % 2 === 0, - [styles.blue]: value % 2 === 1, - }); - const onClick = () => dispatch(setValue({ - value: value + 1, - })); - - return ( - <label> - {props.label}: - <button className={classes} onClick={onClick}> - {value} - </button> - </label> - ); -} - -Counter.propTypes = { - label: PropTypes.string.isRequired, -}; diff --git a/minimal-app/src/features/counter/counter.module.css b/minimal-app/src/features/counter/counter.module.css deleted file mode 100644 index d78b8d90518fd3f4f5164a814fd59cc0ca248550..0000000000000000000000000000000000000000 --- a/minimal-app/src/features/counter/counter.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.red { - color: rgba(255 0 0 / 100%); -} - -.blue { - color: rgba(0 0 255 / 100%); -} diff --git a/minimal-app/src/features/counter/counter.test.js b/minimal-app/src/features/counter/counter.test.js deleted file mode 100644 index fedc10fb91fae823bf5da3e62469f7e9c22c5a35..0000000000000000000000000000000000000000 --- a/minimal-app/src/features/counter/counter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import '../../testing/mockRedux.js'; - -import { Counter } from './counter.js'; - -import { - selectValue, - setValue, -} from './counterSlice.js'; -jest.mock('./counterSlice.js', () => ({ - selectValue: jest.fn().mockName('selectValue'), - setValue: jest.fn().mockName('setValue'), -})); - -describe('the button', () => { - test('displays the value from the store', () => { - selectValue.mockReturnValue(9999); - render(<Counter label={'Foo'} />); - expect(screen.getByRole('button')).toHaveTextContent(/^9999$/); - }); - test('is red when the value from the store is even', () => { - selectValue.mockReturnValue(9998); - render(<Counter label={'Foo'} />); - expect(screen.getByRole('button')).toHaveClass('red'); - }); - test('is blue when the value from the store is odd', () => { - selectValue.mockReturnValue(9999); - render(<Counter label={'Foo'} />); - expect(screen.getByRole('button')).toHaveClass('blue'); - }); - test('increments the value in the store when clicked', async() => { - selectValue.mockReturnValue(9999); - render(<Counter label={'Foo'} />); - await userEvent.click(screen.getByRole('button')); - expect(setValue).toHaveBeenCalledTimes(1); - expect(setValue).toHaveBeenCalledWith({ - value: 9999 + 1, - }); - }); -}); diff --git a/minimal-app/src/features/counter/counterSlice.js b/minimal-app/src/features/counter/counterSlice.js deleted file mode 100644 index 60b530ea9df1ea8926e7d47066d33e4c9e27c061..0000000000000000000000000000000000000000 --- a/minimal-app/src/features/counter/counterSlice.js +++ /dev/null @@ -1,25 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; - -const counterSlice = createSlice({ - name: 'counter', - initialState: { - value: 0, - }, - reducers: { - setValue: (counter, action) => { - const { - value, - } = action.payload; - counter.value = value; - }, - }, -}); -export default counterSlice; - -export const { - setValue, -} = counterSlice.actions; - -export function selectValue(state) { - return state.counter.value; -} diff --git a/minimal-app/src/features/counter/counterSlice.test.js b/minimal-app/src/features/counter/counterSlice.test.js deleted file mode 100644 index b98407b1e8cf41316473c4ff7dd560eb16d6b55d..0000000000000000000000000000000000000000 --- a/minimal-app/src/features/counter/counterSlice.test.js +++ /dev/null @@ -1,36 +0,0 @@ -import counterSlice, { - selectValue, - setValue, -} from './counterSlice.js'; - -describe('the initial state', () => { - test('has a value of zero', () => { - const state = counterSlice.reducer(undefined, {}); - expect(state).toEqual({ - value: 0, - }); - }); -}); - -describe('selectValue', () => { - test('reads the stored value', () => { - const state = { - value: 9999, - }; - const result = selectValue({ [counterSlice.name]: state }); - expect(result).toBe(9999); - }); -}); - -describe('setValue', () => { - test('overwrites the stored value', () => { - const state = counterSlice.reducer({ - value: 8888, - }, setValue({ - value: 9999, - })); - expect(state).toEqual({ - value: 9999, - }); - }); -}); diff --git a/minimal-app/src/index.css b/minimal-app/src/index.css deleted file mode 100644 index 97ab24b2c00ece55c9cda463bf87733c1e24b902..0000000000000000000000000000000000000000 --- a/minimal-app/src/index.css +++ /dev/null @@ -1,41 +0,0 @@ -:root { - /* Colors */ - --letterbox-color: rgba(0 0 0 / 100%); - --app-background-color: rgba(239 239 239 / 100%); - --font-color: rgba(0 0 0 / 100%); - - /* Sizes */ - --minimum-app-size: 300px; -} - -body { - margin: 0; - font-family: sans-serif; - color: var(--font-color); -} - -#root { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background: var(--letterbox-color); -} - -#portrait { - position: relative; - margin: auto; - min-width: var(--minimum-app-size); - min-height: var(--minimum-app-size); - width: 100%; - height: 100%; - max-width: 62.5vh; - background: var(--app-background-color); - overflow: hidden; - transform: scale(1); -} - -button { - -webkit-tap-highlight-color: transparent; -} diff --git a/minimal-app/src/index.js b/minimal-app/src/index.js deleted file mode 100644 index 98a67e4729efd6f3b4562a19667906f766cb9d53..0000000000000000000000000000000000000000 --- a/minimal-app/src/index.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; -import { Provider } from 'react-redux'; -import { HashRouter as Router } from 'react-router-dom'; - -import { store } from './app/store.js'; -import { App } from './app.js'; - -import './index.css'; - -createRoot(document.getElementById('root')).render( - <React.StrictMode> - <Provider store={store}> - <Router> - <div id="portrait"> - <App /> - </div> - </Router> - </Provider> - </React.StrictMode>, -); diff --git a/minimal-app/src/setupTests.js b/minimal-app/src/setupTests.js deleted file mode 100644 index 666127af390a138ec802783a327366a743bb7188..0000000000000000000000000000000000000000 --- a/minimal-app/src/setupTests.js +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom/extend-expect'; diff --git a/minimal-app/src/testing/mockRedux.js b/minimal-app/src/testing/mockRedux.js deleted file mode 100644 index 53195fd58a6864c48ad5a66fd85882135db71fd8..0000000000000000000000000000000000000000 --- a/minimal-app/src/testing/mockRedux.js +++ /dev/null @@ -1,11 +0,0 @@ -export const mockDispatch = jest.fn().mockName('dispatch'); - -jest.mock('react-redux', () => ({ - useSelector: jest.fn((selector) => { - if (selector.mock === undefined) { - throw new Error(`Call to unmocked selector ${selector.name}`); - } - return selector(); - }).mockName('useSelector'), - useDispatch: jest.fn().mockName('useDispatch').mockReturnValue(mockDispatch), -})); diff --git a/package.json b/package.json index b1cdc8932e49669c96851da14e0985f8c7da265f..d651dc4061605467256394ddc34981c7c089bd0e 100644 --- a/package.json +++ b/package.json @@ -7,15 +7,15 @@ "scripts": { "postinstall:stylelint-config": "cd stylelint-config && npm install", "postinstall:eslint-config": "cd eslint-config && npm install", - "postinstall:app": "cd minimal-app && npm install", + "postinstall:app": "cd algorithm-explorer && npm install", "postinstall": "run-s postinstall:**", - "lint:app": "cd minimal-app && npm run lint", + "lint:app": "cd algorithm-explorer && npm run lint", "lint": "run-s --continue-on-error lint:**", - "test-once:app": "cd minimal-app && npm run test-once", + "test-once:app": "cd algorithm-explorer && npm run test-once", "test-once": "run-s --continue-on-error test-once:**", "test": "run-s test-once", - "start": "cd minimal-app && npm run start", - "build:app": "cd minimal-app && npm run build", + "start": "cd algorithm-explorer && npm run start", + "build:app": "cd algorithm-explorer && npm run build", "build": "run-s build:**" }, "devDependencies": {