Upload files

Password-Manager
This commit is contained in:
ZorahM 2025-05-08 20:09:15 +00:00
parent 2bf2336006
commit 03d85eb262
2 changed files with 213 additions and 2 deletions

View File

@ -1,3 +1,47 @@
# Password-Manager # Менеджер паролей
Менеджер паролей на HTML. ## Описание
Простой веб-менеджер паролей, созданный с использованием HTML, TailwindCSS и JavaScript. Приложение позволяет пользователям вводить, хранить, сортировать и копировать пароли в удобной таблице. Данные сохраняются локально в браузере (localStorage), что обеспечивает доступ к паролям при повторных посещениях страницы.
## Основные функции
- **Добавление паролей**: Ввод данных в формате `Сервис Логин Пароль`.
- **Автоматическое сохранение**: Пароли сохраняются в localStorage после добавления.
- **Сортировка**: Возможность сортировки таблицы по любому столбцу (Сервис, Логин, Пароль) нажатием на заголовок столбца.
- **Копирование паролей**: Кнопка для копирования пароля в буфер обмена.
- **Современный дизайн**: Интерфейс с закругленными углами, градиентным фоном и цветовой схемой в красно-белых тонах.
## Технологии
- **HTML5**: Для структуры страницы.
- **TailwindCSS**: Для стилизации интерфейса.
- **JavaScript**: Для обработки данных, сортировки и работы с localStorage.
## Установка и запуск
1. Склонируйте репозиторий:
```
git clone https://github.com/<ваш-репозиторий>.git
```
2. Откройте файл `index.html` в браузере:
```
open index.html
```
Или используйте локальный сервер для запуска (например, через VS Code с расширением Live Server).
## Использование
1. Введите данные в текстовое поле в формате `Сервис Логин Пароль` (каждая запись с новой строки).
2. Нажмите кнопку **Добавить**.
3. Данные отобразятся в таблице, автоматически сохранятся и будут доступны при следующем посещении.
4. Нажмите на заголовок столбца, чтобы отсортировать таблицу.
5. Нажмите на кнопку 📋 рядом с паролем, чтобы скопировать его.
## Пример ввода
```
Сервис Логин Пароль
Gmail user123 Password!2023
```
## Ограничения
- Данные хранятся в localStorage, что означает, что они доступны только в том браузере, где были сохранены.
- Приложение не шифрует пароли — используйте его только для тестовых данных или в безопасной среде.
## Лицензия
Проект распространяется под лицензией MIT. Подробности в файле `LICENSE`.

167
index.html Normal file
View File

@ -0,0 +1,167 @@
<script type="text/javascript">
var gk_isXlsx = false;
var gk_xlsxFileLookup = {};
var gk_fileData = {};
function filledCell(cell) {
return cell !== '' && cell != null;
}
function loadFileData(filename) {
if (gk_isXlsx && gk_xlsxFileLookup[filename]) {
try {
var workbook = XLSX.read(gk_fileData[filename], { type: 'base64' });
var firstSheetName = workbook.SheetNames[0];
var worksheet = workbook.Sheets[firstSheetName];
// Convert sheet to JSON to filter blank rows
var jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, blankrows: false, defval: '' });
// Filter out blank rows (rows where all cells are empty, null, or undefined)
var filteredData = jsonData.filter(row => row.some(filledCell));
// Heuristic to find the header row by ignoring rows with fewer filled cells than the next row
var headerRowIndex = filteredData.findIndex((row, index) =>
row.filter(filledCell).length >= filteredData[index + 1]?.filter(filledCell).length
);
// Fallback
if (headerRowIndex === -1 || headerRowIndex > 25) {
headerRowIndex = 0;
}
// Convert filtered JSON back to CSV
var csv = XLSX.utils.aoa_to_sheet(filteredData.slice(headerRowIndex)); // Create a new sheet from filtered array of arrays
csv = XLSX.utils.sheet_to_csv(csv, { header: 1 });
return csv;
} catch (e) {
console.error(e);
return "";
}
}
return gk_fileData[filename] || "";
}
</script><!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Менеджер паролей</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
background: linear-gradient(to bottom, #fff5f5, #ffffff);
}
</style>
</head>
<body class="min-h-screen font-sans">
<!-- Main Section -->
<section class="container mx-auto px-4 py-12 max-w-3xl">
<h1 class="text-4xl font-bold text-red-600 mb-4">Менеджер паролей</h1>
<p class="text-gray-600 mb-8">Введите свои данные в формате: Сервис Логин Пароль. Пароли сохраняются автоматически.</p>
<div class="bg-white p-6 rounded-3xl shadow-lg">
<textarea id="inputData" class="w-full p-4 border rounded-2xl mb-4 bg-gray-50 focus:outline-none focus:ring-2 focus:ring-red-400 text-sm resize-y" rows="5" placeholder="Введите данные в формате: Сервис Логин Пароль (каждая запись с новой строки)"></textarea>
<button onclick="parsePasswords()" class="w-full bg-red-500 text-white p-3 rounded-2xl hover:bg-red-600 transition duration-300 font-semibold">Добавить</button>
<div id="output" class="mt-6"></div>
</div>
</section>
<script>
let tableData = [];
// Load existing passwords from local storage on page load
window.onload = function() {
const savedData = localStorage.getItem('passwords');
if (savedData) {
tableData = JSON.parse(savedData);
renderTable();
}
};
function parsePasswords() {
const input = document.getElementById('inputData').value;
const output = document.getElementById('output');
output.innerHTML = '';
const lines = input.trim().split('\n');
if (lines.length === 0 || lines[0] === '') {
renderTable();
return;
}
lines.forEach(line => {
const parts = line.trim().split(' ');
if (parts.length >= 3) {
const password = parts.pop();
const login = parts.pop();
const service = parts.join(' ');
if (service && login && password) {
tableData.push({ service, login, password });
}
}
});
localStorage.setItem('passwords', JSON.stringify(tableData));
document.getElementById('inputData').value = '';
renderTable();
}
function renderTable() {
const output = document.getElementById('output');
output.innerHTML = '';
if (tableData.length === 0) {
output.innerHTML = '<p class="text-red-500 text-center font-medium">Пожалуйста, введите данные!</p>';
return;
}
const table = document.createElement('table');
table.className = 'w-full border-collapse rounded-2xl overflow-hidden shadow-md';
let header = table.insertRow();
const headers = ['Сервис', 'Логин', 'Пароль'];
let sortDirection = { 0: 1, 1: 1, 2: 1 }; // 1 for ascending, -1 for descending
headers.forEach((text, index) => {
const th = document.createElement('th');
th.textContent = text;
th.className = 'border border-gray-200 p-4 bg-red-50 text-gray-700 font-semibold text-left cursor-pointer';
th.addEventListener('click', () => {
sortTable(index, sortDirection[index]);
sortDirection[index] *= -1;
renderTable();
});
header.appendChild(th);
});
tableData.forEach((row, rowIndex) => {
const tableRow = table.insertRow();
let i = 0;
for (let key in row) {
const td = tableRow.insertCell();
const text = row[key];
td.className = 'border border-gray-200 p-4 bg-white text-sm break-words max-w-xs';
const copyBtn = document.createElement('button');
copyBtn.textContent = '📋';
copyBtn.className = 'ml-2 text-blue-500 hover:text-blue-700';
copyBtn.onclick = (e) => {
e.stopPropagation();
navigator.clipboard.writeText(text).then(() => alert('Пароль скопирован!'));
};
td.appendChild(document.createTextNode(text));
td.appendChild(copyBtn);
i++;
}
});
output.appendChild(table);
}
function sortTable(columnIndex, direction) {
tableData.sort((a, b) => {
const keys = ['service', 'login', 'password'];
const valueA = a[keys[columnIndex]];
const valueB = b[keys[columnIndex]];
return direction * valueA.localeCompare(valueB);
});
localStorage.setItem('passwords', JSON.stringify(tableData));
}
</script>
</body>
</html>