Skip to content

Commit

Permalink
Password generator (#677)
Browse files Browse the repository at this point in the history
* completed the generator

* completed password generator

* resolved issues
  • Loading branch information
Drex72 authored Oct 5, 2023
1 parent 5b29e40 commit 0a713c3
Show file tree
Hide file tree
Showing 3 changed files with 343 additions and 1 deletion.
238 changes: 238 additions & 0 deletions packages/kitchen-sink/src/examples/password-generator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import { useState, useEffect, useRef } from 'react';
import { block } from 'million/react';
import { BsClipboardCheck } from 'react-icons/bs';
import { FiRefreshCcw } from 'react-icons/fi';

const PasswordGenerator = block(() => {
const {
copyPasswordToClipboard,
password,
passwordInputRef,
setPassword,
generatePassword,
} = useGeneratePassword();
return (
<div className="password_generator">
<h1>Password Generator</h1>

<p>
Create strong and secure passwords to keep your account safe online.
</p>

<div className="password_generator_top_section">
{/* Password Generator Output */}
<div className="password_generator_output_container">
<input
ref={passwordInputRef}
type="text"
readOnly
value={password.value}
/>

<Tooltip text="Copy to Clipboard" show={password.isCopied}>
<button
type="button"
className="right-icon"
onClick={copyPasswordToClipboard}
>
<BsClipboardCheck />
</button>
</Tooltip>
</div>

<button
type="button"
className="password_generator_refresh_password"
onClick={generatePassword}
>
<FiRefreshCcw />
</button>
</div>

{/* Options */}

<div className="password_generator_customizable_options">
<div className="password_generator_customizable_options__length">
<label>Length: {password.length}</label>
<input
type="range"
min="3"
max="100"
value={password.length}
className="timeline"
onChange={(e) => {
setPassword({
...password,
length: parseInt(e.target.value),
});
}}
/>
</div>

<div className="password_generator_customizable_options__others">
<div className="password_generator_customizable_options__password_type">
<label>Password Type: </label>
<select
value={password.password_type}
onChange={(e) =>
setPassword({
...password,
password_type: e.target.value as IPasswordType,
})
}
>
<option value={'password'}>Password</option>
<option value={'pin'}>PIN</option>
</select>
</div>

<div className="password_generator_customizable_options__password_type">
<input
id="number_checkbox"
name="number_checkbox"
disabled={password.password_type === 'pin'}
type="checkbox"
checked={password.numbers!}
onChange={() =>
setPassword({ ...password, numbers: !password.numbers })
}
className="password_generator_customizable_options__checkbox"
/>
<label htmlFor="number_checkbox">Number</label>
</div>

<div className="password_generator_customizable_options__password_type">
<input
id="symbol_checkbox"
name="symbol_checkbox"
type="checkbox"
disabled={password.password_type === 'pin'}
onChange={() =>
setPassword({ ...password, symbols: !password.symbols })
}
className="password_generator_customizable_options__checkbox"
/>
<label htmlFor="symbol_checkbox">Symbols</label>
</div>
</div>
</div>
</div>
);
});

export default PasswordGenerator;

const Tooltip = ({ text, children, show }: IToolTipProps) => {
return (
<div className="password_generator_tooltip-container">
<div>{children}</div>
<p className={`password_generator_tooltip-text ${show ? 'visible' : ''}`}>
{text}
</p>
</div>
);
};

type IPasswordType = 'password' | 'pin';

interface IPasswordState {
value: string;
password_type: IPasswordType;
length: number;
isCopied: boolean;
numbers?: boolean;
symbols?: boolean;
}

interface IToolTipProps {
children: JSX.Element;
text: string;
show: boolean;
}

interface IGeneratePassword {
includeNumbers: boolean;
includeSymbols: boolean;
passwordLength: number;
password_type: IPasswordType;
}

const useGeneratePassword = () => {
const passwordInputRef = useRef<HTMLInputElement | null>(null);

const [password, setPassword] = useState<IPasswordState>({
value: '',
password_type: 'password',
length: 3,
isCopied: false,
numbers: false,
symbols: false,
});

const copyPasswordToClipboard = () => {
if (passwordInputRef.current) {
passwordInputRef.current.select();
document.execCommand('copy');

// Deselect the text
window.getSelection()?.removeAllRanges();

setPassword({ ...password, isCopied: true });

setTimeout(() => {
setPassword({ ...password, isCopied: false });
}, 3000);
}
};

const generatePassword = () => {
const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz';
const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numberChars = '0123456789';
const symbolChars = '!@#$%^&*()_+{}[]|:;"<>,.?/~';

let charset = '';

if (password.password_type === 'password') {
charset += lowercaseChars + uppercaseChars;

if (password.numbers) {
charset += numberChars;
}

if (password.symbols) {
charset += symbolChars;
}
}

if (password.password_type === 'pin') {
charset += numberChars;
}

let generatedValue = '';

for (let i = 0; i < password.length; i++) {
const randomIndex = Math.floor(Math.random() * charset.length);
generatedValue += charset[randomIndex];
}

setPassword({ ...password, value: generatedValue });
};

useEffect(() => {
generatePassword();
}, [
password.length,
password.numbers,
password.password_type,
password.symbols,
]);

return {
passwordInputRef,
password,
setPassword,
copyPasswordToClipboard,
generatePassword,
};
};
104 changes: 104 additions & 0 deletions packages/kitchen-sink/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,107 @@ input[type='range'] {
}
}
}

/********** PASSWORD GENERATOR **********/
.password_generator {
width: 80%;
margin: 2em auto;
}

.password_generator_top_section {
display: flex;
gap: 1.5em;
}

.password_generator_output_container {
display: flex;
border-radius: 10px;
background: #353535;
border: 1px solid #dddddd;
align-items: center;
padding-right: 20px;
flex: 5;
}

.password_generator_output_container input {
padding: 14px;
width: 100%;
outline: none;
line-height: 30px;
caret-color: #1c1c1c;
background-color: transparent;
font-size: 16px;
border-radius: 10px;
transition: all 0.3s ease-in;
color: #fff;
font-weight: 600;
font-size: 1.5rem;
}

.password_generator_output_container .right-icon {
font-size: 25px;
cursor: pointer;
border: none;
}

.password_generator_refresh_password {
flex: 0.5;
}

.password_generator_tooltip-container {
position: relative;
}

.password_generator_tooltip-text {
background-color: #333;
color: #fff;
text-align: center;
border-radius: 4px;
padding: 6px;
position: absolute;
z-index: 1;
bottom: 50%;
left: 90%;
font-size: 12px;
opacity: 0;
transition: all 200ms ease-in-out;
}

.password_generator_tooltip-text.visible {
opacity: 1;
}

.password_generator_customizable_options {
}

.password_generator_customizable_options__length {
display: flex;
align-items: center;
}

.password_generator_customizable_options__checkbox {
position: relative;
/* border: 1px solid themed("primary"); */
border-radius: 4px;
background: none;
cursor: pointer;
line-height: 0;
margin: 0 0.6em 0 0;
outline: 0;
padding: 0 !important;
vertical-align: text-top;
height: 18px;
width: 18px;
opacity: 0.5;
transition: all 200ms ease-in-out;

&:hover {
opacity: 1;
}

&:checked {
/* background-color: themed("primary"); */
opacity: 1;
border: none;
}
}
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 comments on commit 0a713c3

@vercel
Copy link

@vercel vercel bot commented on 0a713c3 Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

sink – ./packages/kitchen-sink

sink-millionjs.vercel.app
sink-git-main-millionjs.vercel.app
million-kitchen-sink-atit.vercel.app
sink.million.dev

@vercel
Copy link

@vercel vercel bot commented on 0a713c3 Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

million-kitchen-sink – ./packages/kitchen-sink

million-kitchen-sink.vercel.app
million-kitchen-sink-git-main-millionjs.vercel.app
million-kitchen-sink-millionjs.vercel.app

Please sign in to comment.