diff --git a/assets/css/styles.css b/assets/css/styles.css new file mode 100644 index 0000000..bcaa1f5 --- /dev/null +++ b/assets/css/styles.css @@ -0,0 +1,299 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +body { + background-color: #0f172a; + color: #f8fafc; + min-height: 100vh; + padding: 20px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.container { + max-width: 900px; + width: 100%; + display: grid; + grid-template-columns: 1fr; + gap: 30px; +} + +@media (min-width: 768px) { + .container { + grid-template-columns: 1fr 1fr; + } +} + +.header { + text-align: center; + margin-bottom: 20px; + grid-column: 1 / -1; +} + +.header h1 { + font-size: 2.5rem; + margin-bottom: 10px; + background: linear-gradient(90deg, #3b82f6, #8b5cf6); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.header p { + font-size: 1.1rem; + color: #cbd5e1; + max-width: 600px; + margin: 0 auto; + line-height: 1.6; +} + +.card { + background: linear-gradient(145deg, #1e293b, #334155); + border-radius: 16px; + padding: 30px; + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); + border: 1px solid #475569; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 15px 30px rgba(0, 0, 0, 0.4); +} + +.card-title { + font-size: 1.5rem; + margin-bottom: 20px; + display: flex; + align-items: center; + gap: 10px; + color: #e2e8f0; +} + +.card-title i { + color: #60a5fa; +} + +.input-group { + margin-bottom: 20px; +} + +label { + display: block; + margin-bottom: 8px; + font-weight: 500; + color: #cbd5e1; +} + +.password-container { + position: relative; + display: flex; + align-items: center; +} + +input[type="text"], +input[type="password"] { + width: 100%; + padding: 15px; + background-color: #1e293b; + border: 2px solid #475569; + border-radius: 10px; + color: #f1f5f9; + font-size: 1.1rem; + transition: border-color 0.3s; +} + +input[type="text"]:focus, +input[type="password"]:focus { + outline: none; + border-color: #60a5fa; +} + +.toggle-password { + position: absolute; + right: 15px; + background: none; + border: none; + color: #94a3b8; + cursor: pointer; + font-size: 1.2rem; +} + +.strength-indicator { + height: 8px; + background-color: #475569; + border-radius: 4px; + margin-top: 15px; + overflow: hidden; +} + +.strength-bar { + height: 100%; + width: 0%; + border-radius: 4px; + transition: width 0.5s ease, background-color 0.5s ease; +} + +.strength-text { + margin-top: 10px; + font-size: 0.9rem; + text-align: right; + font-weight: 600; +} + +.criteria-list { + list-style: none; + margin-top: 20px; +} + +.criteria-list li { + margin-bottom: 10px; + display: flex; + align-items: center; + gap: 10px; +} + +.criteria-list i { + width: 20px; + text-align: center; +} + +.valid { + color: #10b981; +} + +.invalid { + color: #ef4444; +} + +.generate-options { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 15px; + margin-bottom: 25px; +} + +.option-group { + display: flex; + align-items: center; + gap: 8px; +} + +.option-group input[type="checkbox"], +.option-group input[type="number"] { + width: auto; +} + +.option-group label { + margin-bottom: 0; + font-size: 0.95rem; +} + +.length-slider { + width: 100%; + margin: 15px 0; +} + +.length-value { + text-align: center; + font-weight: bold; + font-size: 1.2rem; + color: #60a5fa; +} + +.btn { + background: linear-gradient(90deg, #3b82f6, #6366f1); + color: white; + border: none; + padding: 15px 25px; + font-size: 1rem; + font-weight: 600; + border-radius: 10px; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + width: 100%; + margin-top: 10px; +} + +.btn:hover { + background: linear-gradient(90deg, #2563eb, #4f46e5); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(59, 130, 246, 0.4); +} + +.btn:active { + transform: translateY(0); +} + +.result-password { + margin-top: 25px; + background-color: #1e293b; + padding: 15px; + border-radius: 10px; + border: 1px solid #475569; + word-break: break-all; + font-family: monospace; + font-size: 1.2rem; + text-align: center; + color: #10b981; + display: none; +} + +.result-password.show { + display: block; +} + +.copy-btn { + background-color: #475569; + color: white; + border: none; + padding: 8px 15px; + border-radius: 6px; + cursor: pointer; + margin-top: 10px; + transition: background-color 0.3s; +} + +.copy-btn:hover { + background-color: #64748b; +} + +.footer { + text-align: center; + margin-top: 40px; + color: #94a3b8; + font-size: 0.9rem; + grid-column: 1 / -1; +} + +.tips { + margin-top: 30px; + background-color: rgba(30, 41, 59, 0.7); + padding: 20px; + border-radius: 10px; + border-left: 4px solid #3b82f6; +} + +.tips h3 { + margin-bottom: 10px; + color: #e2e8f0; +} + +.tips ul { + padding-left: 20px; + color: #cbd5e1; +} + +.tips li { + margin-bottom: 8px; +} \ No newline at end of file diff --git a/assets/js/script.js b/assets/js/script.js new file mode 100644 index 0000000..5e43f7c --- /dev/null +++ b/assets/js/script.js @@ -0,0 +1,173 @@ +// Elementos del DOM +const passwordInput = document.getElementById('password-input'); +const togglePasswordBtn = document.getElementById('toggle-password'); +const strengthBar = document.getElementById('strength-bar'); +const strengthText = document.getElementById('strength-text'); + +// Iconos de criterios de validación +const lengthIcon = document.getElementById('length-icon'); +const uppercaseIcon = document.getElementById('uppercase-icon'); +const lowercaseIcon = document.getElementById('lowercase-icon'); +const numberIcon = document.getElementById('number-icon'); +const specialIcon = document.getElementById('special-icon'); + +// Elementos para generación de contraseñas +const uppercaseCheckbox = document.getElementById('uppercase-checkbox'); +const lowercaseCheckbox = document.getElementById('lowercase-checkbox'); +const numbersCheckbox = document.getElementById('numbers-checkbox'); +const symbolsCheckbox = document.getElementById('symbols-checkbox'); +const lengthSlider = document.getElementById('length-slider'); +const lengthValue = document.getElementById('length-value'); +const generateBtn = document.getElementById('generate-btn'); +const resultPassword = document.getElementById('result-password'); +const generatedPassword = document.getElementById('generated-password'); +const copyBtn = document.getElementById('copy-btn'); + +// Caracteres para generar contraseñas +const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; +const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz'; +const numberChars = '0123456789'; +const symbolChars = '!@#$%^&*()_+-=[]{}|;:,.<>?'; + +// Mostrar/ocultar contraseña +togglePasswordBtn.addEventListener('click', function () { + const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password'; + passwordInput.setAttribute('type', type); + this.innerHTML = type === 'password' ? '' : ''; +}); + +// Validar contraseña en tiempo real +passwordInput.addEventListener('input', validatePassword); + +// Actualizar valor del slider de longitud +lengthSlider.addEventListener('input', function () { + lengthValue.textContent = this.value; +}); + +// Generar contraseña +generateBtn.addEventListener('click', generatePassword); + +// Copiar contraseña generada +copyBtn.addEventListener('click', copyPassword); + +// Función para validar la contraseña +function validatePassword() { + const password = passwordInput.value; + let strength = 0; + let criteriaMet = 0; + + // Criterios de validación + const hasMinLength = password.length >= 8; + const hasUppercase = /[A-Z]/.test(password); + const hasLowercase = /[a-z]/.test(password); + const hasNumber = /\d/.test(password); + const hasSpecial = /[!@#$%^&*]/.test(password); + + // Actualizar iconos de criterios + updateCriteriaIcon(lengthIcon, hasMinLength); + updateCriteriaIcon(uppercaseIcon, hasUppercase); + updateCriteriaIcon(lowercaseIcon, hasLowercase); + updateCriteriaIcon(numberIcon, hasNumber); + updateCriteriaIcon(specialIcon, hasSpecial); + + // Calcular fortaleza + if (hasMinLength) strength += 20; + if (hasUppercase) strength += 20; + if (hasLowercase) strength += 20; + if (hasNumber) strength += 20; + if (hasSpecial) strength += 20; + + // Actualizar barra y texto de fortaleza + strengthBar.style.width = strength + '%'; + + if (strength <= 20) { + strengthBar.style.backgroundColor = '#ef4444'; + strengthText.textContent = 'Fortaleza: Muy débil'; + } else if (strength <= 40) { + strengthBar.style.backgroundColor = '#f97316'; + strengthText.textContent = 'Fortaleza: Débil'; + } else if (strength <= 60) { + strengthBar.style.backgroundColor = '#eab308'; + strengthText.textContent = 'Fortaleza: Moderada'; + } else if (strength <= 80) { + strengthBar.style.backgroundColor = '#84cc16'; + strengthText.textContent = 'Fortaleza: Fuerte'; + } else { + strengthBar.style.backgroundColor = '#10b981'; + strengthText.textContent = 'Fortaleza: Muy fuerte'; + } +} + +// Función para actualizar iconos de criterios +function updateCriteriaIcon(iconElement, isValid) { + if (isValid) { + iconElement.className = 'fas fa-check-circle valid'; + } else { + iconElement.className = 'fas fa-times-circle invalid'; + } +} + +// Función para generar contraseña +function generatePassword() { + // Verificar que al menos una opción esté seleccionada + if (!uppercaseCheckbox.checked && !lowercaseCheckbox.checked && + !numbersCheckbox.checked && !symbolsCheckbox.checked) { + alert('Selecciona al menos un tipo de carácter para generar la contraseña.'); + return; + } + + // Construir el conjunto de caracteres disponibles + let availableChars = ''; + if (uppercaseCheckbox.checked) availableChars += uppercaseChars; + if (lowercaseCheckbox.checked) availableChars += lowercaseChars; + if (numbersCheckbox.checked) availableChars += numberChars; + if (symbolsCheckbox.checked) availableChars += symbolChars; + + // Generar la contraseña + const length = parseInt(lengthSlider.value); + let password = ''; + + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * availableChars.length); + password += availableChars[randomIndex]; + } + + // Mostrar la contraseña generada + generatedPassword.textContent = password; + resultPassword.classList.add('show'); + + // También poner la contraseña generada en el campo de validación + passwordInput.value = password; + passwordInput.type = 'text'; + togglePasswordBtn.innerHTML = ''; + validatePassword(); +} + +// Función para copiar la contraseña al portapapeles +function copyPassword() { + const passwordText = generatedPassword.textContent; + + if (!passwordText) { + alert('No hay contraseña para copiar. Genera una contraseña primero.'); + return; + } + + // Usar la API del portapapeles + navigator.clipboard.writeText(passwordText).then(() => { + // Cambiar temporalmente el texto del botón + const originalText = copyBtn.innerHTML; + copyBtn.innerHTML = ' ¡Copiada!'; + copyBtn.style.backgroundColor = '#10b981'; + + setTimeout(() => { + copyBtn.innerHTML = originalText; + copyBtn.style.backgroundColor = ''; + }, 2000); + }).catch(err => { + console.error('Error al copiar: ', err); + alert('No se pudo copiar la contraseña. Inténtalo de nuevo.'); + }); +} + +// Validar contraseña al cargar la página (para estado inicial) +validatePassword(); \ No newline at end of file diff --git a/index.php b/index.php index 6325f2c..eb813c3 100644 --- a/index.php +++ b/index.php @@ -1,3 +1,112 @@ - + + + + + Validador y Generador de Contraseñas Seguras + + + + +
+
+

Validador y Generador de Contraseñas

+

Verifica la fortaleza de tus contraseñas y genera nuevas contraseñas seguras con nuestros herramientas gratuitas.

+
+ +
+

Validar Contraseña

+
+ +
+ + +
+
+
+
+
Fortaleza: Muy débil
+
+ + + +
+

Consejos para contraseñas seguras:

+
    +
  • Usa una combinación de letras, números y símbolos
  • +
  • Evita información personal como nombres o fechas
  • +
  • No reutilices contraseñas en diferentes servicios
  • +
  • Considera usar un gestor de contraseñas
  • +
+
+
+ +
+

Generar Contraseña Segura

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ + +
+ + + +
+
+ +
+ +
+

Características de una buena contraseña:

+
    +
  • Longitud mínima de 12 caracteres
  • +
  • Combinación de diferentes tipos de caracteres
  • +
  • Sin patrones obvios o secuencias
  • +
  • Fácil de recordar pero difícil de adivinar
  • +
+
+
+ + +
-echo "Hola Mundo"; \ No newline at end of file + + + \ No newline at end of file