Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,26 @@ button:hover {
display: block;
}

.results h2 {
.results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
flex-wrap: wrap;
gap: 1rem;
}

.results h2 {
margin: 0;
}

.visibility-controls {
display: flex;
align-items: center;
}

.visibility-controls .checkbox-item {
margin-bottom: 0;
}

.passwords-list {
Expand All @@ -181,6 +199,21 @@ button:hover {
align-items: center;
}

.password-text {
font-family: 'Courier New', monospace;
font-size: 0.9rem;
flex: 1;
margin-right: 1rem;
word-break: break-all;
transition: all 0.3s ease;
}

.password-text.hidden {
filter: blur(5px);
user-select: none;
cursor: default;
}

.password-item button {
background: none;
border: none;
Expand Down Expand Up @@ -418,6 +451,11 @@ input:checked + .theme-slider {
input:checked + .slider:before {
transform: translateX(24px);
}

.results-header {
flex-direction: column;
align-items: flex-start;
}
}

@media screen and (max-width: 480px) {
Expand Down Expand Up @@ -453,6 +491,22 @@ input:checked + .theme-slider {
input:checked + .slider:before {
transform: translateX(22px);
}

.results-header {
flex-direction: column;
align-items: flex-start;
}

.password-item {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}

.password-text {
margin-right: 0;
width: 100%;
}
}

@media screen and (max-height: 480px) and (orientation: landscape) {
Expand All @@ -470,6 +524,10 @@ input:checked + .theme-slider {
.slider:before, .slider {
transition: none;
}

.password-text {
transition: none;
}
}

@media (prefers-contrast: high) {
Expand Down
10 changes: 9 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,15 @@ <h1>Secure Password Generator</h1>
<button id="generateBtn">Generate Passwords</button>

<div class="results" id="results">
<h2>Generated Passwords</h2>
<div class="results-header">
<h2>Generated Passwords</h2>
<div class="visibility-controls">
<div class="checkbox-item">
<input type="checkbox" id="showPasswords" checked>
<label for="showPasswords">Show Passwords</label>
</div>
</div>
</div>
<div class="passwords-list" id="passwordsList"></div>
</div>
</main>
Expand Down
46 changes: 38 additions & 8 deletions js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const translations = {
numPasswords: "Number of Passwords:",
generateBtn: "Generate Passwords",
generatedPasswords: "Generated Passwords",
showPasswords: "Show Passwords",
copy: "Copy",
copied: "Copied!",
error: "Error",
Expand All @@ -56,6 +57,7 @@ const translations = {
numPasswords: "パスワードの数:",
generateBtn: "パスワードを生成",
generatedPasswords: "生成されたパスワード",
showPasswords: "パスワードを表示",
copy: "コピー",
copied: "コピー完了!",
error: "エラー",
Expand Down Expand Up @@ -144,6 +146,7 @@ function updateUILanguage(language) {
document.querySelector('label[for="ensureOne"]').textContent = texts.ensureOne;
document.querySelector('label[for="noRepeats"]').textContent = texts.noRepeats;
document.querySelector('label[for="numPasswords"]').textContent = texts.numPasswords;
document.querySelector('label[for="showPasswords"]').textContent = texts.showPasswords;

// Update button text
document.getElementById('generateBtn').textContent = texts.generateBtn;
Expand Down Expand Up @@ -263,6 +266,20 @@ function showLanguageIndicator(language) {
}, 1500);
}

// Function to toggle password visibility
function togglePasswordVisibility() {
const showPasswords = document.getElementById('showPasswords').checked;
const passwordTexts = document.querySelectorAll('.password-text');

passwordTexts.forEach(passwordText => {
if (showPasswords) {
passwordText.classList.remove('hidden');
} else {
passwordText.classList.add('hidden');
}
});
}

// UI Event Handlers
document.addEventListener('DOMContentLoaded', () => {
// Initialize language
Expand Down Expand Up @@ -292,6 +309,7 @@ document.addEventListener('DOMContentLoaded', () => {
const generateBtn = document.getElementById('generateBtn');
const specialCharsCheckbox = document.getElementById('specialChars');
const specialCharsInput = document.getElementById('specialCharsInput');
const showPasswordsCheckbox = document.getElementById('showPasswords');

// Create language indicator element
const languageIndicator = document.createElement('div');
Expand All @@ -303,6 +321,9 @@ document.addEventListener('DOMContentLoaded', () => {
specialCharsInput.style.display = specialCharsCheckbox.checked ? 'block' : 'none';
});

// Show/hide passwords event listener
showPasswordsCheckbox.addEventListener('change', togglePasswordVisibility);

generateBtn.addEventListener('click', () => {
const minLength = parseInt(document.getElementById('minLength').value);
const maxLength = parseInt(document.getElementById('maxLength').value);
Expand All @@ -314,22 +335,25 @@ document.addEventListener('DOMContentLoaded', () => {
const ensureOneOfEach = document.getElementById('ensureOne').checked;
const numPasswords = parseInt(document.getElementById('numPasswords').value);
const excludeChars = document.getElementById('excludeChars').value;
const showPasswords = document.getElementById('showPasswords').checked;

// Validate inputs
if (minLength > maxLength) {
alert('Minimum length cannot be greater than maximum length');
const language = document.documentElement.getAttribute('data-language') || 'en';
const errorMsg = language === 'en'
? 'Minimum length cannot be greater than maximum length'
: '最小長は最大長より大きくできません';
alert(errorMsg);
return;
}

const passwordsList = document.getElementById('passwordsList');
passwordsList.innerHTML = '';

try {

const language = document.documentElement.getAttribute('data-language') || 'en';
const texts = translations[language];


// Generate passwords
for (let i = 0; i < numPasswords; i++) {
const password = generatePassword(
Expand All @@ -342,14 +366,20 @@ document.addEventListener('DOMContentLoaded', () => {
const passwordItem = document.createElement('div');
passwordItem.className = 'password-item';

// Use textContent to safely display the password
// Create password text element with proper class for show/hide functionality
const passwordText = document.createElement('span');
passwordText.className = 'password-text';
passwordText.textContent = `${i + 1}. ${password}`;

// Apply initial visibility state
if (!showPasswords) {
passwordText.classList.add('hidden');
}

passwordItem.appendChild(passwordText);

// Create the copy button and append it
const copyButton = document.createElement('button');

copyButton.textContent = texts.copy;
copyButton.onclick = () => copyToClipboard(password, copyButton);
passwordItem.appendChild(copyButton);
Expand All @@ -361,7 +391,9 @@ document.addEventListener('DOMContentLoaded', () => {
// Show results
document.getElementById('results').classList.add('show');
} catch (error) {
alert(error.message);
const language = document.documentElement.getAttribute('data-language') || 'en';
const errorMsg = language === 'en' ? error.message : 'エラーが発生しました: ' + error.message;
alert(errorMsg);
}
});
});
Expand All @@ -374,13 +406,11 @@ function copyToClipboard(text, button) {
navigator.clipboard.writeText(text).then(() => {
const originalText = button.textContent;
button.textContent = texts.copied;

button.disabled = true;

// Reset button after 1.5 seconds
setTimeout(() => {
button.textContent = texts.copy;

button.disabled = false;
}, 1500);
}).catch(err => {
Expand Down