Skip to content

Commit

Permalink
feat: add length control and new visuals
Browse files Browse the repository at this point in the history
  • Loading branch information
javigaralva committed Nov 3, 2022
1 parent bd94dd9 commit e374b70
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 84 deletions.
54 changes: 54 additions & 0 deletions src/components/javigaralva/colorized-letter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { CSSProperties } from 'react'
import { sample } from './utils/sample'
import { getVerticalLinesStyle } from './styles/getVerticalLinesStyle'
import { getSquareAndVerticalLinesStyle } from './styles/getSquareAndVerticalLinesStyle'
import { getBigCircleDottedStyle } from './styles/getBigCircleDottedStyle'
import { getBigDotsStyle } from './styles/getBigDotsStyle'
import { isUpperCaseLetter } from './utils/is-upper-case-letter'
import { isSymbol } from './utils/is-symbol'
import { isNumber } from './utils/is-number'

type ColorizedLetterStyles = {
classNames: string
style: CSSProperties
}

interface ColorizedLetterProps {
letter: string
}
export function ColorizedLetter({ letter }: ColorizedLetterProps) {
const { classNames, style } = getStyles(letter)
return (
<span className={classNames} style={style}>
{letter}
</span>
)
}

function getStyles(letter: string): ColorizedLetterStyles {
let classNames = 'text-white'
let style: CSSProperties = {}
if (isNumber(letter)) {
classNames = 'text-orange-600'
style = getBigDotsStyle()
} else if (isSymbol(letter)) {
classNames = 'text-lime-600'
style = getBigCircleDottedStyle()
style.textShadow = 'rgb(116 255 77 / 60%) -1px -1px 6px, rgb(124 127 255 / 0%) 1px 1px 6px'
} else if (isUpperCaseLetter(letter)) {
classNames = 'text-white/50'
style = getSquareAndVerticalLinesStyle()
} else {
classNames = 'text-white px-4'
style = getVerticalLinesStyle()
}

const duration = sample(['duration-500', 'duration-700', 'duration-1000'])

classNames = `${duration} hover:scale-150 inline-block ${classNames}`

return {
classNames,
style
}
}
14 changes: 14 additions & 0 deletions src/components/javigaralva/colorized-password.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ColorizedLetter } from './colorized-letter'

interface ColorizedPasswordProps {
password: string
}
export function ColorizedPassword({ password }: ColorizedPasswordProps) {
return (
<div className='font-mono font-black text-4xl min-h-min tracking-widest cursor-pointer'>
{password.split('').map((letter, i) => (
<ColorizedLetter key={i} letter={letter} />
))}
</div>
)
}
7 changes: 7 additions & 0 deletions src/components/javigaralva/constants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const LETTERS = 'abcdefghijklmnopqrstuvwxyz'
export const NUMBERS = '0123456789'
export const SYMBOLS = '\'\\¡!"·$%&()=€@[]{}^/+-*'
export const UPPER_CASE_LETTERS_LIST = LETTERS.toUpperCase().split('')
export const LOWER_CASE_LETTERS_LIST = LETTERS.toLowerCase().split('')
export const NUMBERS_LIST = NUMBERS.split('')
export const SYMBOLS_LIST = SYMBOLS.split('')
137 changes: 53 additions & 84 deletions src/components/javigaralva/password-generator-app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { useState, CSSProperties } from 'react'
import { useState, useEffect, type ChangeEventHandler } from 'react'
import { sample } from './utils/sample'
import { ColorizedPassword } from './colorized-password'
import {
UPPER_CASE_LETTERS_LIST,
LOWER_CASE_LETTERS_LIST,
NUMBERS_LIST,
SYMBOLS_LIST
} from './constants'

interface GeneratePasswordOptions {
length: number
Expand All @@ -7,8 +15,10 @@ interface GeneratePasswordOptions {
hasNumbers: boolean
hasSymbols: boolean
}
const MIN_PASSWORD_LENGTH = 1
const MAX_PASSWORD_LENGTH = 30
const DEFAULT_PASSWORD_OPTIONS: GeneratePasswordOptions = {
length: 24,
length: 10,
hasUpperCaseLetters: true,
hasLowerCaseLetters: true,
hasNumbers: true,
Expand Down Expand Up @@ -40,14 +50,6 @@ function getChoosableStrategies(options: GeneratePasswordOptions) {
].filter(Boolean)
}

const LETTERS = 'abcdefghijklmnopqrstuvwxyz'
const NUMBERS = '0123456789'
const SYMBOLS = '\'\\¡!"·$%&()=€@[]{}^/+-*'
const UPPER_CASE_LETTERS_LIST = LETTERS.toUpperCase().split('')
const LOWER_CASE_LETTERS_LIST = LETTERS.toLowerCase().split('')
const NUMBERS_LIST = NUMBERS.split('')
const SYMBOLS_LIST = SYMBOLS.split('')

const sampleUpperCaseLetter = makeSampleCharacterFunction(UPPER_CASE_LETTERS_LIST)
const sampleLowerCaseLetter = makeSampleCharacterFunction(LOWER_CASE_LETTERS_LIST)
const sampleNumber = makeSampleCharacterFunction(NUMBERS_LIST)
Expand All @@ -57,88 +59,55 @@ function makeSampleCharacterFunction(characters: string[]) {
return () => sample(characters)
}

function sample<T>(arr: T[]) {
return arr[Math.floor(Math.random() * arr.length)]
}

function colorizePassword(password: string) {
return password.split('').map((letter, i) => {
let className = 'text-white'
const style: CSSProperties = {}
if (NUMBERS.includes(letter)) {
className = 'text-orange-600'
const width = 128 + random(-100, 100)
const offset = 154 + random(-100, 100)
const alpha = 2 + random(-1, 6)
style.outlineOffset = `${offset}px`
style.outlineColor = `rgb(234 88 12 / ${alpha}%)`
style.outlineWidth = `${width}px`
style.outlineStyle = 'dotted'
style.borderRadius = '50%'
} else if (SYMBOLS.includes(letter)) {
className = 'text-lime-600'
style.textShadow = 'rgb(116 255 77 / 60%) -1px -1px 6px, rgb(124 127 255 / 0%) 1px 1px 6px'
const width = 8 + random(-4, 2)
const offset = 204 + random(-100, 100)
const alpha = 6 + random(-2, 2)
style.outlineOffset = `${offset}px`
style.outlineColor = `rgb(14 249 29 / ${alpha}%)`
style.outlineWidth = `${width}px`
style.outlineStyle = 'dotted'
style.borderRadius = '50%'
} else if (UPPER_CASE_LETTERS_LIST.includes(letter)) {
className = 'text-white/50'
const width = 28 + random(-10, 10)
const offset = 54 + random(-50, 50)
style.outlineOffset = `${offset}px`
style.outlineColor = 'rgb(219 219 219 / 2%)'
style.outlineWidth = `${width}px`
style.outlineStyle = 'dashed'
const thickness = 380 + random(-200, 100)
const alpha = 4 + random(-2, 2)
style.textDecorationLine = 'underline'
style.textDecorationColor = `rgb(219 219 219 / ${alpha}%)`
style.textDecorationThickness = `${thickness}px`
} else {
const thickness = 380 + random(-200, 100)
const alpha = 4 + random(-2, 2)
style.textDecorationLine = 'overline'
style.textDecorationColor = `rgb(219 219 219 / ${alpha}%)`
style.textDecorationThickness = `${thickness}px`
className = 'text-white p-4'
}
return (
<span key={letter + i} className={className} style={style}>
{letter}
</span>
)
})
}

function random(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min)
}

export default function Main() {
const [password, setPassword] = useState(generatePassword(DEFAULT_PASSWORD_OPTIONS))
const [passwordLength, setPasswordLength] = useState(DEFAULT_PASSWORD_OPTIONS.length)
const [password, setPassword] = useState('')

const handleGeneratePassword = () => {
setPassword(generatePassword(DEFAULT_PASSWORD_OPTIONS))
setPassword(
generatePassword({
...DEFAULT_PASSWORD_OPTIONS,
length: passwordLength
})
)
}

const handleOnChangeSlider: ChangeEventHandler<HTMLInputElement> = (e) => {
setPasswordLength(Number(e.target.value))
}

useEffect(() => {
setPassword(
generatePassword({
...DEFAULT_PASSWORD_OPTIONS,
length: passwordLength
})
)
}, [passwordLength])

return (
<div className='w-screen h-screen bg-stone-800'>
<div className='flex items-center place-content-center h-screen'>
<div className='flex flex-col min-w-100 w-6/12 place-items-center gap-10'>
<div className='text-slate-300 font-mono font-black text-4xl min-h-min tracking-widest break-all text-center'>
{colorizePassword(password)}
<div className='flex place-content-center h-screen'>
<div className='flex flex-col min-w-100 place-items-center justify-evenly'>
<div className='min-h-min mx-10 text-center mt-32'>
<ColorizedPassword password={password} />
</div>
<div className='flex flex-col place-items-center gap-10'>
<button
className='bg-yellow-600 rounded min-w-fit font-black uppercase py-2 w-60 text-lg text-black/75 tracking-wide duration-300 hover:shadow-yellow-400/25 scale-100 hover:bg-yellow-500 active:scale-95 shadow-2xl shadow-slate-900'
onClick={handleGeneratePassword}
>
Generate
</button>
<input
className='w-60 h-1 outline-2 rounded-lg outline-dotted outline-offset-8 outline-slate-50/25 appearance-none cursor-pointer bg-yellow-600/50 accent-yellow-600'
type='range'
min={MIN_PASSWORD_LENGTH}
max={MAX_PASSWORD_LENGTH}
value={passwordLength}
onChange={handleOnChangeSlider}
/>
</div>
<button
className='bg-yellow-600 min-w-fit w-96 text-lg font-black uppercase py-2 rounded-md'
onClick={handleGeneratePassword}
>
Generate Password
</button>
</div>
</div>
</div>
Expand Down
16 changes: 16 additions & 0 deletions src/components/javigaralva/styles/getBigCircleDottedStyle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { CSSProperties } from 'react'
import { random } from '../utils/random'

export function getBigCircleDottedStyle() {
const style: CSSProperties = {}
const width = 8 + random(-4, 2)
const offset = 204 + random(-100, 100)
const alpha = 6 + random(-2, 2)
const color = 124 + random(-25, 75)
style.outlineOffset = `${offset}px`
style.outlineColor = `hsl(${color}deg 100% 50% / ${alpha}%)`
style.outlineWidth = `${width}px`
style.outlineStyle = 'dotted'
style.borderRadius = '50%'
return style
}
16 changes: 16 additions & 0 deletions src/components/javigaralva/styles/getBigDotsStyle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { CSSProperties } from 'react'
import { random } from '../utils/random'

export function getBigDotsStyle() {
const style: CSSProperties = {}
const width = 128 + random(-100, 100)
const offset = 154 + random(-100, 100)
const alpha = 2 + random(-1, 6)
const color = 0 + random(-10, 40)
style.outlineOffset = `${offset}px`
style.outlineColor = `hsl(${color}deg 100% 50% / ${alpha}%)`
style.outlineWidth = `${width}px`
style.outlineStyle = 'dotted'
style.borderRadius = '50%'
return style
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { CSSProperties } from 'react'
import { random } from '../utils/random'

export function getSquareAndVerticalLinesStyle() {
const style: CSSProperties = {}
{
const width = 28 + random(-10, 10)
const alpha = 4 + random(-2, 2)
const offset = 54 + random(-50, 50)
const color = 0 + random(50, 100)
style.outlineOffset = `${offset}px`
style.outlineColor = `hsl(${color}deg 100% 50% / ${alpha}%)`
style.outlineWidth = `${width}px`
style.outlineStyle = 'dashed'
}
{
const thickness = 380 + random(-200, 100)
const alpha = 4 + random(-2, 2)
const color = 0 + random(100, 150)
style.textDecorationLine = 'underline'
style.textDecorationColor = `hsl(${color}deg 100% 50% / ${alpha}%)`
style.textDecorationThickness = `${thickness}px`
}
return style
}
13 changes: 13 additions & 0 deletions src/components/javigaralva/styles/getVerticalLinesStyle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CSSProperties } from 'react'
import { random } from '../utils/random'

export function getVerticalLinesStyle() {
const style: CSSProperties = {}
const thickness = 380 + random(-200, 100)
const alpha = 4 + random(-2, 2)
style.textDecorationLine = 'overline'
const color = 0 + random(50, 100)
style.textDecorationColor = `hsl(${color}deg 100% 50% / ${alpha}%)`
style.textDecorationThickness = `${thickness}px`
return style
}
5 changes: 5 additions & 0 deletions src/components/javigaralva/utils/is-number.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { NUMBERS } from '../constants'

export function isNumber(letter: string) {
return NUMBERS.includes(letter)
}
5 changes: 5 additions & 0 deletions src/components/javigaralva/utils/is-symbol.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SYMBOLS } from '../constants'

export function isSymbol(letter: string) {
return SYMBOLS.includes(letter)
}
5 changes: 5 additions & 0 deletions src/components/javigaralva/utils/is-upper-case-letter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { UPPER_CASE_LETTERS_LIST } from '../constants'

export function isUpperCaseLetter(letter: string) {
return UPPER_CASE_LETTERS_LIST.includes(letter)
}
3 changes: 3 additions & 0 deletions src/components/javigaralva/utils/random.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function random(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
3 changes: 3 additions & 0 deletions src/components/javigaralva/utils/sample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function sample<T>(arr: T[]) {
return arr[Math.floor(Math.random() * arr.length)]
}

0 comments on commit e374b70

Please sign in to comment.