Password-Manager/index.html
ZorahM 03d85eb262 Upload files
Password-Manager
2025-05-08 20:09:15 +00:00

167 lines
7.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>