First Commit

This commit is contained in:
Josh S 2023-03-11 18:34:00 -05:00 committed by GitHub
parent 1b0f36a39f
commit c0bae65c80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 341 additions and 0 deletions

7
README.md Normal file
View file

@ -0,0 +1,7 @@
# A simple password generator built in `React.js`
`npm install`
`npm start`
# For build production run `npm run build`

33
package.json Normal file
View file

@ -0,0 +1,33 @@
{
"name": "password-gen",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"react-toastify": "^9.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

12
public/index.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Password Generator</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

3
public/robots.txt Normal file
View file

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

188
src/App.jsx Normal file
View file

@ -0,0 +1,188 @@
import { React, useState} from 'react';
import { toast, ToastContainer} from 'react-toastify';
import './Assets/CSS/App.min.css';
import { numbers, upperCaseLetters, lowerCaseLetters, specialCharacters } from './Components/Characters';
import 'react-toastify/dist/ReactToastify.css';
import { COPY_SUCCESS } from './Components/Message';
function App() {
const [password, setPassword] = useState('')
const [passwordLength, setPasswordLength] = useState(20)
const [includeUppercase, setIncludeUppercase] = useState(false)
const [includeLowercase, setIncludeLowercase] = useState(false)
const [includeNumbers, setIncludeNumbers] = useState(false)
const [includeSymbols, setIncludeSymbols] = useState(false)
const handleGeneratePassword = (e) => {
if (
!includeUppercase &&
!includeLowercase &&
!includeNumbers &&
!includeSymbols
) {
notify('Error! You must select atleast one option.', true)
}
let characterList = ''
if (includeLowercase) {
characterList = characterList + lowerCaseLetters
}
if (includeUppercase) {
characterList = characterList + upperCaseLetters
}
if (includeNumbers) {
characterList = characterList + numbers
}
if (includeSymbols) {
characterList = characterList + specialCharacters
}
setPassword(createPassword(characterList))
}
const createPassword = (characterList) => {
let password = ''
const characterListLength = characterList.length
for (let i = 0; i < passwordLength; i++) {
const characterIndex = Math.round(Math.random() * characterListLength)
password = password + characterList.charAt(characterIndex)
}
return password
}
const copyToClipboard = () => {
const newTextArea = document.createElement('textarea')
newTextArea.innerText = password
document.body.appendChild(newTextArea)
newTextArea.select()
document.execCommand('copy')
newTextArea.remove()
}
const notify = (message, hasError = false) => {
if (hasError) {
toast.error(message, {
position: 'top-center',
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: false,
progress: undefined,
})
} else {
toast(message, {
position: 'top-center',
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: false,
progress: undefined,
})
}
}
const handleCopyPassword = (e) => {
if(password === '') {
notify('Error! Nothing to copy', true)
} else {
copyToClipboard()
notify(COPY_SUCCESS)
}
}
return (
<div className="App">
<div className="container">
<div className="generator">
<h2 className="generator__header">Simple Password Generator</h2>
<div className="generator__password">
<h3>{password}</h3>
<button onClick={handleCopyPassword} className='copy__btn'>
<i className="far fa-clipboard"></i>
</button>
</div>
<div className="form-group">
<label className='passgen-text' htmlFor='password-strength'>Password Length</label>
<input
defaultValue={passwordLength}
onChange={(e) => setPasswordLength(e.target.value)}
type='number'
id='password-strength'
name='password-strength'
max='22'
min='10'
/>
</div>
<div className="form-group">
<label className='passgen-text' htmlFor='uppercase-letters'>Include Upppercase Characters</label>
<input
checked={includeUppercase}
onChange={(e) => setIncludeUppercase(e.target.checked)}
type='checkbox'
id='uppercase-letters'
name='uppercase-letters'
/>
</div>
<div className="form-group">
<label className='passgen-text' htmlFor='lowercase-letters'>Include Lowercase Characters</label>
<input
checked={includeLowercase}
onChange={(e) => setIncludeLowercase(e.target.checked)}
type='checkbox'
id='lowercase-letters'
name='lowercase-letters'
/>
</div>
<div className="form-group">
<label className='passgen-text' htmlFor='include-numbers'>Include Numbers</label>
<input
checked={includeNumbers}
onChange={(e) => setIncludeNumbers(e.target.checked)}
type='checkbox'
id='include-numbers'
name='include-numbers'
/>
</div>
<div className="form-group">
<label className='passgen-text' htmlFor='include-symbols'>Include Symbols</label>
<input
checked={includeSymbols}
onChange={(e) => setIncludeSymbols(e.target.checked)}
type='checkbox'
id='include-symbols'
name='include-symbols'
/>
</div>
<button onClick={handleGeneratePassword} className="generator__btn">
Generate
</button>
<ToastContainer
position='top-center'
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick={true}
rtl={false}
pauseOnFocusLoss={false}
draggable={false}
/>
</div>
</div>
</div>
)
}
export default App

77
src/Assets/CSS/App.min.css vendored Normal file
View file

@ -0,0 +1,77 @@
@import url(https://fonts.bunny.net/css?family=abril-fatface:400|rubik:600,800i,900i);
.App {
min-height: 100vh;
background-color: #101725;
}
.container {
width: 350px;
margin: 0 auto;
padding-top: 200px;
}
.generator {
background-color: #0b0f19;
border-radius: 3px;
box-shadow: 0px 2px 10px rgba(255, 255, 255, 0.2);
padding: 20px;
}
.generator__header {
text-align: center;
color: white;
margin-bottom: 20px;
font-family: 'Abril Fatface', display;
font-family: 'Rubik', sans-serif;
}
.generator__password {
position: relative;
background-color: #101725;
padding: 13px 10px;
color: white;
height: 46px;
margin-bottom: 15px;
font-family: 'Abril Fatface', display;
font-family: 'Rubik', sans-serif;
}
.copy__btn {
position: absolute;
background-color: #3b3b98;
color: white;
border: none;
height: 40px;
padding: 10;
cursor: pointer;
top: 3px;
right: 3x;
}
.generator__btn {
background-color: #101725;
border: none;
display: block;
width: 100%;
padding: 10px;
color: white;
font-size: 17px;
cursor: pointer;
font-family: 'Abril Fatface', display;
font-family: 'Rubik', sans-serif;
}
.form-group {
display: flex;
justify-content: space-between;
color: white;
margin-bottom: 15px;
font-family: 'Abril Fatface', display;
font-family: 'Rubik', sans-serif;
}
.passgen-text {
font-family: 'Abril Fatface', display;
font-family: 'Rubik', sans-serif;
}

5
src/Assets/CSS/Index.min.css vendored Normal file
View file

@ -0,0 +1,5 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

View file

@ -0,0 +1,4 @@
export const numbers = '0123456789'
export const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
export const lowerCaseLetters = 'abcdefghijklmnopqrstuvwxyz'
export const specialCharacters = "!'^+%&/()=?_#$½§{[]}|;:>÷`<.*-@é"

View file

@ -0,0 +1 @@
export const COPY_SUCCESS = 'Password successfully copied to clipboard'

11
src/index.js Normal file
View file

@ -0,0 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './Assets/CSS/Index.min.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('app')
)