Initial commit

This commit is contained in:
Lncvrt committed 2026-10-11 12:28:48 -07:00
commit c2149baf8e
13 files changed
+899

No files matched your search

+72
View File
@@ -0,0 +1,72 @@
@import "tailwindcss";
body {
@apply bg-black text-white text-center select-none p-4 min-h-screen flex items-center justify-center;
--col0: rgb(8, 8, 8);
--col1: rgb(16, 16, 16);
--col2: rgb(32, 32, 32);
--col3: rgb(48, 48, 48);
--col4: rgb(64, 64, 64);
--col5: rgb(80, 80, 80);
--col6: rgb(96, 96, 96);
--col7: rgb(112, 112, 112);
}
h1 {
@apply mb-2;
}
p {
@apply mb-4;
}
.form {
@apply flex flex-col items-center gap-2 mb-4;
}
.slider-section {
@apply flex flex-col items-center w-full;
}
#password-length {
@apply w-full;
}
button {
@apply bg-(--col1) hover:bg-(--col3) border border-(--col3) hover:border-(--col5) rounded-lg cursor-pointer transition-all;
}
.preset-buttons,
.char-selection-buttons {
@apply flex gap-2 flex-wrap justify-center;
}
.preset-btn,
.char-selection-buttons button {
@apply px-2 py-1;
}
.char-selection-buttons button.char-selected {
@apply bg-(--col3) hover:bg-(--col5) border-(--col5) hover:border-(--col7) -translate-y-0.5;
}
.generate-btn {
@apply px-4 py-2;
}
.result-section {
@apply flex flex-col items-center justify-center mt-2;
}
.password-display {
@apply w-full mb-2 p-2 bg-(--col1) border border-(--col3) rounded-lg wrap-break-word text-sm max-h-48 overflow-y-auto select-text;
}
.result-buttons {
@apply flex flex-row gap-2.5 justify-center items-center;
}
.copy-btn {
@apply px-4 py-2;
}
+138
View File
@@ -0,0 +1,138 @@
import './App.css'
import { useState, useEffect, useCallback } from 'react'
function App () {
const [password, setPassword] = useState('')
const [length, setLength] = useState(8)
const [copied, setCopied] = useState(false)
const [useUpper, setUseUpper] = useState<boolean>(true)
const [useLower, setUseLower] = useState<boolean>(true)
const [useNumbers, setUseNumbers] = useState<boolean>(true)
const [useSymbols, setUseSymbols] = useState<boolean>(true)
const presets = [8, 16, 32, 64, 128]
const charsUpper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const charsLower = 'abcdefghijklmnopqrstuvwxyz'
const charsNumber = '0123456789'
const charsSymbols = '!@#$%^&*'
const generatePassword = useCallback(() => {
const chars =
(useUpper ? charsUpper : '') +
(useLower ? charsLower : '') +
(useNumbers ? charsNumber : '') +
(useSymbols ? charsSymbols : '')
if (chars == '') return setPassword('')
setPassword(
Array.from(
{ length },
() => chars[Math.floor(Math.random() * chars.length)]
).join('')
)
}, [length, useUpper, useLower, useNumbers, useSymbols])
const copyToClipboard = () => {
if (password.trim().length == 0) return
navigator.clipboard.writeText(password)
setCopied(true)
setTimeout(() => setCopied(false), 1000)
}
useEffect(() => {
setTimeout(() => generatePassword(), 0)
}, [generatePassword])
return (
<main className='w-full max-w-200 mx-auto'>
<p className='text-3xl font-bold'>Password Generator</p>
<p>Select a length, or use the slider for a custom value.</p>
<form
className='form'
onSubmit={e => {
e.preventDefault()
generatePassword()
}}
>
<div className='slider-section'>
<label htmlFor='password-length'>Password Length: {length}</label>
<input
id='password-length'
type='range'
min='1'
max='500'
value={length}
onChange={e => setLength(Number(e.target.value))}
step='1'
/>
</div>
<div className='preset-buttons'>
{presets.map(preset => (
<button
key={preset}
type='button'
className='preset-btn'
onClick={() => setLength(preset)}
>
{preset}
</button>
))}
</div>
</form>
<p>Characters to use</p>
<div className='char-selection-buttons'>
<button
type='button'
className={useUpper ? 'char-selected' : ''}
onClick={() => setUseUpper(!useUpper)}
>
Use uppercase
</button>
<button
type='button'
className={useLower ? 'char-selected' : ''}
onClick={() => setUseLower(!useLower)}
>
Use lowercases
</button>
<button
type='button'
className={useNumbers ? 'char-selected' : ''}
onClick={() => setUseNumbers(!useNumbers)}
>
Use numbers
</button>
<button
type='button'
className={useSymbols ? 'char-selected' : ''}
onClick={() => setUseSymbols(!useSymbols)}
>
Use symbols
</button>
</div>
<div className='result-section'>
<p className='password-display'>
{password.trim().length == 0 ? '(none)' : password}
</p>
<div className='result-buttons'>
<button
className='copy-btn'
onClick={copyToClipboard}
disabled={copied}
>
{copied ? 'Copied' : 'Copy'}
</button>
<button className='copy-btn' onClick={generatePassword}>
Regenerate
</button>
</div>
</div>
</main>
)
}
export default App
+1
View File
@@ -0,0 +1 @@
declare module '@fontsource/lexend'
+9
View File
@@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
)