First Commit
This commit is contained in:
parent
1b0f36a39f
commit
c0bae65c80
10 changed files with 341 additions and 0 deletions
7
README.md
Normal file
7
README.md
Normal 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
33
package.json
Normal 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
12
public/index.html
Normal 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
3
public/robots.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
188
src/App.jsx
Normal file
188
src/App.jsx
Normal 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
77
src/Assets/CSS/App.min.css
vendored
Normal 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
5
src/Assets/CSS/Index.min.css
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
4
src/Components/Characters.js
Normal file
4
src/Components/Characters.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export const numbers = '0123456789'
|
||||
export const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
export const lowerCaseLetters = 'abcdefghijklmnopqrstuvwxyz'
|
||||
export const specialCharacters = "!'^+%&/()=?_#$½§{[]}|;:>÷`<.*-@é"
|
||||
1
src/Components/Message.js
Normal file
1
src/Components/Message.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const COPY_SUCCESS = 'Password successfully copied to clipboard'
|
||||
11
src/index.js
Normal file
11
src/index.js
Normal 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')
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue