diff --git a/README.md b/README.md index 654751a020be83440142f0f142d987d1b65227cd..5a65499ff5f154ee72ed7d078ccf65beac47ec43 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,9 @@ Sorting Visualizer demonstrates how Bubble Sort works through an interactive gra [Check it out](https://sorting-visualizer-stdarunte-0b3511e20a59a622aed5caf7134ac4faf2.h-da.io/) --- -unsorted: + +#### unsorted:  -sorted: +#### sorted:  diff --git a/package-lock.json b/package-lock.json index ebb7f242a4a0ba3bb7fba80996c657eff4a70a4b..6354186b2832c3f97488a264750f3948744a8957 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,9 @@ "name": "sorting-visualizer", "version": "0.0.0", "dependencies": { + "bootstrap": "^5.3.3", "react": "^18.3.1", + "react-bootstrap": "^2.10.4", "react-bootstrap-range-slider": "^3.0.8", "react-dom": "^18.3.1" }, @@ -278,7 +280,6 @@ "version": "7.25.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", - "peer": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -937,7 +938,6 @@ "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -947,7 +947,6 @@ "version": "3.9.5", "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.5.tgz", "integrity": "sha512-xEwGKoysu+oXulibNUSkXf8itW0npHHTa6c4AyYeZIJyRoegeteYuFpZUBPtIDE8RfHdNsSmE1ssOkxRnwbkuQ==", - "peer": true, "dependencies": { "@swc/helpers": "^0.5.0" }, @@ -962,7 +961,6 @@ "version": "0.4.16", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", - "peer": true, "dependencies": { "dequal": "^2.0.3" }, @@ -974,7 +972,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", - "peer": true, "dependencies": { "@babel/runtime": "^7.21.0", "@popperjs/core": "^2.11.6", @@ -995,7 +992,6 @@ "version": "8.0.4", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", - "peer": true, "peerDependencies": { "react": ">=16.14.0" } @@ -1212,7 +1208,6 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -1291,7 +1286,6 @@ "version": "4.4.11", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", - "peer": true, "dependencies": { "@types/react": "*" } @@ -1299,8 +1293,7 @@ "node_modules/@types/warning": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", - "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", - "peer": true + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" }, "node_modules/@vitejs/plugin-react": { "version": "4.3.1", @@ -1536,6 +1529,24 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1803,7 +1814,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "peer": true, "engines": { "node": ">=6" } @@ -1824,7 +1834,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "peer": true, "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -2694,7 +2703,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "peer": true, "dependencies": { "loose-envify": "^1.0.0" } @@ -3494,7 +3502,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "peer": true, "dependencies": { "react-is": "^16.3.2", "warning": "^4.0.0" @@ -3547,7 +3554,6 @@ "version": "2.10.4", "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.4.tgz", "integrity": "sha512-W3398nBM2CBfmGP2evneEO3ZZwEMPtHs72q++eNw60uDGDAdiGn0f9yNys91eo7/y8CTF5Ke1C0QO8JFVPU40Q==", - "peer": true, "dependencies": { "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", @@ -3607,8 +3613,7 @@ "node_modules/react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", - "peer": true + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "node_modules/react-refresh": { "version": "0.14.2", @@ -3623,7 +3628,6 @@ "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "peer": true, "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -3659,8 +3663,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "peer": true + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", @@ -4057,8 +4060,7 @@ "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "peer": true + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/type-check": { "version": "0.4.0", @@ -4164,7 +4166,6 @@ "version": "7.2.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", - "peer": true, "dependencies": { "@babel/runtime": "^7.6.3", "@types/react": ">=16.9.11", @@ -4277,7 +4278,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "peer": true, "dependencies": { "loose-envify": "^1.0.0" } diff --git a/package.json b/package.json index 2a9eb5277656a82d7d1d31c1684aefed5dfdef01..0c3679eb5c9f4dae773f95179934707b74fe23b7 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "preview": "vite preview" }, "dependencies": { + "bootstrap": "^5.3.3", "react": "^18.3.1", + "react-bootstrap": "^2.10.4", "react-bootstrap-range-slider": "^3.0.8", "react-dom": "^18.3.1" }, diff --git a/src/SortingVisualizer.css b/src/SortingVisualizer.css index 1fb138a020fcc0b1206ae24dc30d4206c5da8c04..b809978693962dd52d19f68cf1bb30ef7fe6b2e3 100644 --- a/src/SortingVisualizer.css +++ b/src/SortingVisualizer.css @@ -34,14 +34,13 @@ body { } .range-slider { - margin-top: -4px; padding: 0px; } #ToolBar { height: 50px; width: 100%; - background: aquamarine; + background: #34495e; display: flex; flex-direction: row; justify-content: center; @@ -49,29 +48,22 @@ body { } -.Button { +#startButton { + height: 78%; + width: 85px; + font-size: 12px; margin: 10px; - height: 60%; - width: 65px; - background: #66d6d6; + background: #1abc9c; text-align: center; display: grid; place-items: center; border-radius: 5px; border: none; - color: #003d3d; + color: white; font-size: 14px; font-family: Arial, sans-serif; font-weight: bold; -} -#startButton { - height: 70%; - margin: 20px; - background: red; - width: 80px; - scale: 110%; - font-size: 12px; } button:active { @@ -79,11 +71,12 @@ button:active { transform: translateY(2px); } -.SpeedLabel { +.Label { margin: 10px; font-size: 15px; + font-family: Arial, sans-serif; font-weight: bold; - color: #003d3d; + color: white; } .DivArray { @@ -97,6 +90,56 @@ button:active { margin-top: 5px; } +#dropdown-menu { + background-color: #34495e; + border: none; + border-radius: 5px; + margin-top: 15px; +} + + +#dropdown-item { + color: white; + font-size: 16px; + font-weight: normal; + border-radius: 5px; +} + +#dropdown-item:hover { + background-color: #1abc9c; + color: white; +} + +#dropdown { + background: none; + border: none; + border-radius: 0px; + color: white; + fontSize: 14px; + fontWeight: normal; + padding: 0; + height: 100%; + display: flex; + alignItems: center; + place-items: center; + margin-inline: 10px; +} + +#dropdown:hover { + color: #1abc9c; +} + +#dropdown:active { + box-shadow: none; + transform: none; +} + +#dropdown.show { + background-color: #1abc9c; + color: white; +} + + @keyframes ScaleAnimation { 0% { transform: scale(1); diff --git a/src/SortingVisualizer.jsx b/src/SortingVisualizer.jsx index 4f951911cf76d16b6a9f1ad0e5dede0a87bc2ed5..efbc46f917e325e417cd9cc1ecd2ade89003fea7 100644 --- a/src/SortingVisualizer.jsx +++ b/src/SortingVisualizer.jsx @@ -3,13 +3,15 @@ import './SortingVisualizer.css' import BubbleSort from "./BubbleSort"; import RangeSlider from 'react-bootstrap-range-slider'; import 'react-bootstrap-range-slider/dist/react-bootstrap-range-slider.css'; +import {Dropdown} from 'react-bootstrap'; +import 'bootstrap/dist/css/bootstrap.min.css'; function SortingVisualizer() { - const moduloFive = ((window.innerWidth / 22)).toFixed(0) % 5; - const monitorSize = (window.innerWidth / 22).toFixed(0) - moduloFive; - const [BarNumber, setBarNumber] = useState(monitorSize); + const moduloFive = ((window.innerWidth / 45)).toFixed(0) % 5; + const monitorSize = (window.innerWidth / 45).toFixed(0) - moduloFive; + const [BarNumber, setBarNumber] = useState(() => monitorSize > 100 ? 100 : monitorSize); // max of 100 bars const [bars, setbars] = useState(() => generateArray(BarNumber)); const [sorting, setSorting] = useState(false); const [alreadySorted, setAlreadySorted] = useState(); @@ -35,7 +37,6 @@ function SortingVisualizer() { resetBars(); }, [BarNumber]); - function getRandomArbitrary(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } @@ -55,7 +56,7 @@ function SortingVisualizer() { setAlreadySorted(1000); setbars(generateArray(BarNumber)); let ColoredBars = document.getElementsByClassName('sorted'); - document.getElementById('startButton').innerText = 'Sort'; + document.getElementById('startButton').innerText = 'Sort!'; while (ColoredBars.length > 0) { ColoredBars[0].className = 'bar'; } @@ -85,40 +86,61 @@ function SortingVisualizer() { if (alreadySorted == 0) { setIsSorted(true); finishAnimation(); - document.getElementById('startButton').innerText = 'Generate new Bars'; + document.getElementById('startButton').innerText = 'Reset!'; } }, [alreadySorted]); + return ( <> <div className='Container'> <div id='ToolBar'> + <div className="Label">How many Bars?</div> <SliderWithInputFormControl style={{className: 'range-slider'}}/> - <input type='number' max={100} min={0} + <input type='number' max={100} min={0} disabled={sorting} onChange={changeEvent => { let value = Number(changeEvent.target.value); if (value > 100) value = 100; if (value < 5) value = 5; setBarNumber(value); }} defaultValue={BarNumber} - value={BarNumber} style={{width: '50px', margin: '10px'}}/> - <div style={{background: 'gray', height: '85%', width: '2px'}}></div> - <div className="SpeedLabel">Sorting-Speed:</div> - <button className="Button" disabled={sorting} - style={{background: `${sortSpeed == 100 ? 'green' : ''}`}} - onClick={() => setSortSpeed('100')}>Slow - </button> - <button className="Button" disabled={sorting} - style={{background: `${sortSpeed == 40 ? 'green' : ''}`}} - onClick={() => setSortSpeed('40')}>Medium - </button> - <button className="Button" disabled={sorting} - style={{background: `${sortSpeed == 0 ? 'green' : ''}`}} - onClick={() => setSortSpeed('0')}>Fast - </button> - <button id='startButton' className="Button" disabled={sorting} onClick={() => { + value={BarNumber} style={{ + width: '42px', + margin: '10px', + borderRadius: '5px', + border: 'none', + textAlign: 'center' + }}/> + <div style={{background: 'gray', height: '70%', marginLeft: '10px', width: '2px'}}></div> + <Dropdown id="dropdown"> + <Dropdown.Toggle + id="dropdown" + disabled={sorting} + > + Sorting-Speed: { + { + 100: 'Slow', + 40: 'Medium', + 0: 'Fast' + }[sortSpeed] || '' + } + </Dropdown.Toggle> + <Dropdown.Menu id="dropdown-menu"> + <Dropdown.Item id="dropdown-item" onClick={() => setSortSpeed(100)}> + Slow + </Dropdown.Item> + <Dropdown.Item id="dropdown-item" onClick={() => setSortSpeed(40)}> + Medium + </Dropdown.Item> + <Dropdown.Item id="dropdown-item" onClick={() => setSortSpeed(0)}> + Fast + </Dropdown.Item> + </Dropdown.Menu> + </Dropdown> + <button id='startButton' className="Button" disabled={sorting} + style={{background: `${sorting ? 'red' : ''}`}} onClick={() => { handleButton() - }}>{sorting ? 'Sorting...' : 'Sort'}</button> + }}>{sorting ? 'Sorting...' : 'Sort!'}</button> </div> <div className='DivArray'> {bars.map((height, index) => (<div key={index} data-key={index}