<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sistema de Gestão de Dados</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
* { font-family: 'Inter', sans-serif; }
.gradient-bg { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.card-hover { transition: all 0.3s ease; }
.card-hover:hover { transform: translateY(-5px); box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04);}
.fade-in { animation: fadeIn 0.5s ease-in; }
@keyframes fadeIn { from { opacity:0; transform: translateY(10px); } to { opacity:1; transform: translateY(0);} }
<body class="bg-gray-50 min-h-screen">
<!-- Header Navigation -->
<header class="gradient-bg text-white shadow-lg">
<div class="container mx-auto px-4 py-4">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fas fa-database text-2xl"></i>
<h1 class="text-2xl font-bold">Sistema de Gestão</h1>
<nav class="hidden md:flex space-x-6">
<a href="#dashboard" class="hover:text-blue-200 transition-colors">Dashboard</a>
<a href="#dados" class="hover:text-blue-200 transition-colors">Base de Dados</a>
<a href="#configuracoes" class="hover:text-blue-200 transition-colors">Configurações</a>
<button class="md:hidden text-xl"><i class="fas fa-bars"></i></button>
<main class="container mx-auto px-4 py-8">
<!-- Dashboard Section -->
<section id="dashboard" class="fade-in mb-12">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-xl shadow-md card-hover p-6">
<div class="flex items-center justify-between">
<p class="text-gray-500 text-sm">Total de Registos</p>
<h3 class="text-3xl font-bold text-gray-800" id="totalRecords">0</h3>
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center">
<i class="fas fa-table text-blue-600"></i>
<div class="bg-white rounded-xl shadow-md card-hover p-6">
<div class="flex items-center justify-between">
<p class="text-gray-500 text-sm">Sites Integrados</p>
<h3 class="text-3xl font-bold text-gray-800">2</h3>
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center">
<i class="fas fa-link text-green-600"></i>
<div class="bg-white rounded-xl shadow-md card-hover p-6">
<div class="flex items-center justify-between">
<p class="text-gray-500 text-sm">Status do Sistema</p>
<h3 class="text-xl font-bold text-green-600">Operacional</h3>
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center">
<i class="fas fa-check text-green-600"></i>
<!-- Data Management Section -->
<section id="dados" class="fade-in mb-12">
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-xl font-semibold text-gray-800">Gestão de Base de Dados</h2>
<div class="flex flex-wrap gap-4 mb-6">
<button onclick="addNewRecord()" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg transition-colors flex items-center space-x-2">
<i class="fas fa-plus"></i><span>Adicionar Registo</span>
<button onclick="dataManager.exportData()" class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-lg transition-colors flex items-center space-x-2">
<i class="fas fa-download"></i><span>Exportar Dados</span>
<button onclick="clearAllData()" class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-lg transition-colors flex items-center space-x-2">
<i class="fas fa-trash"></i><span>Limpar Tudo</span>
<label for="browserSelect" class="flex items-center space-x-2">
<span>Escolher navegador:</span>
<select id="browserSelect" class="px-3 py-1 border border-gray-300 rounded-lg">
<option value="default">Navegador Padrão</option>
<option value="chrome">Google Chrome</option>
<option value="firefox">Mozilla Firefox</option>
<option value="edge">Microsoft Edge</option>
<option value="opera">Opera</option>
<button id="openLinksBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-6 py-2 rounded-lg transition-colors flex items-center space-x-2">
<i class="fas fa-external-link-alt"></i><span>Abrir todos links</span>
<button id="saveTxtBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white px-6 py-2 rounded-lg transition-colors flex items-center space-x-2">
<i class="fas fa-file-export"></i><span>Guardar em TXT</span>
<!-- Search and Filter -->
<div class="flex flex-col md:flex-row gap-4">
<input type="text" id="searchInput" placeholder="Pesquisar registos..." class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<select id="filterSelect" class="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="all">Todos os Registos</option>
<option value="active">Activos</option>
<option value="inactive">Inactivos</option>
<div class="overflow-x-auto">
<tr class="bg-gray-50 border-b border-gray-200">
<th class="px-4 py-3 text-left text-sm font-medium text-gray-700">ID</th>
<th class="px-4 py-3 text-left text-sm font-medium text-gray-700">Nome</th>
<th class="px-4 py-3 text-left text-sm font-medium text-gray-700">Status</th>
<th class="px-4 py-3 text-left text-sm font-medium text-gray-700">Data</th>
<th class="px-4 py-3 text-left text-sm font-medium text-gray-700">Acções</th>
<tbody id="dataTableBody"></tbody>
<!-- Settings Section -->
<section id="configuracoes" class="fade-in">
<div class="bg-white rounded-xl shadow-lg overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-xl font-semibold text-gray-800">Configurações do Sistema</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<h3 class="text-lg font-medium text-gray-800 mb-4">Sites Configurados</h3>
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center space-x-3">
<i class="fas fa-globe text-blue-600"></i>
<a href="https://codigodozero-mz.blogspot.com/" target="_blank" class="text-gray-700 hover:text-blue-600">codigodozero-mz.blogspot.com</a>
<span class="bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full">Activo</span>
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center space-x-3">
<i class="fas fa-globe text-blue-600"></i>
<a href="https://jesusempoesia.blogspot.com/" target="_blank" class="text-gray-700 hover:text-blue-600">jesusempoesia.blogspot.com</a>
<span class="bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full">Activo</span>
<h3 class="text-lg font-medium text-gray-800 mb-4">Preferências</h3>
<div class="flex items-center justify-between">
<span class="text-gray-700">Modo Escuro</span>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
<div class="flex items-center justify-between">
<span class="text-gray-700">Notificações</span>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" class="sr-only peer" checked>
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4">
<div class="text-center">
<p>© 2025 Sistema de Gestão de Dados. Todos os direitos reservados.</p>
<div class="flex justify-center space-x-4 mt-4">
<a href="#" class="hover:text-blue-300 transition-colors"><i class="fab fa-github text-xl"></i></a>
<a href="#" class="hover:text-blue-300 transition-colors"><i class="fab fa-linkedin text-xl"></i></a>
<a href="#" class="hover:text-blue-300 transition-colors"><i class="fab fa-twitter text-xl"></i></a>
// ==== CLASSE DATA MANAGER ====
this.storageKey = 'systemData';
if (!localStorage.getItem(this.storageKey)) {
settings: { darkMode: false, notifications: true },
'https://codigodozero-mz.blogspot.com/',
'https://jesusempoesia.blogspot.com/'
this.saveData(initialData);
getData() { return JSON.parse(localStorage.getItem(this.storageKey)) || { records: [] }; }
saveData(data) { localStorage.setItem(this.storageKey, JSON.stringify(data)); this.updateDashboard(); }
const data = this.getData();
record.id = Date.now().toString();
record.createdAt = new Date().toISOString();
record.status = 'active';
data.records.unshift(record);
this.showNotification('Registo adicionado com sucesso!', 'success');
const data = this.getData();
data.records = data.records.filter(r => r.id !== id);
this.showNotification('Registo eliminado!', 'warning');
updateRecord(id, updatedData) {
const data = this.getData();
const index = data.records.findIndex(r => r.id === id);
if(index!==-1) { data.records[index] = {...data.records[index], ...updatedData}; this.saveData(data); this.renderDataTable(); this.showNotification('Registo actualizado!', 'success'); }
const data = this.getData();
return data.records.filter(record =>
record.name.toLowerCase().includes(query.toLowerCase()) ||
record.description?.toLowerCase().includes(query.toLowerCase())
const data = this.getData();
document.getElementById('totalRecords').textContent = data.records.length;
const data = this.getData();
const tableBody = document.getElementById('dataTableBody');
if(data.records.length===0){
tableBody.innerHTML = `<tr><td colspan="5" class="px-4 py-8 text-center text-gray-500">
<i class="fas fa-inbox text-4xl mb-2"></i>
<p>Nenhum registo encontrado</p>
<button onclick="addNewRecord()" class="mt-4 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors">Adicionar Primeiro Registo</button>
tableBody.innerHTML = data.records.map(record => `
<tr class="border-b border-gray-200 hover:bg-gray-50 transition-colors">
<td class="px-4 py-3 text-sm text-gray-700">${record.id.slice(-6)}</td>
<td class="px-4 py-3"><div class="text-sm font-medium text-gray-900">${record.name}</div>${record.description ? `<div class="text-sm text-gray-500">${record.description}</div>` : ''}</td>
<td class="px-4 py-3"><span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${record.status==='active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">${record.status==='active' ? 'Activo':'Inactivo'}</span></td>
<td class="px-4 py-3 text-sm text-gray-500">${new Date(record.createdAt).toLocaleDateString('pt-PT')}</td>
<td class="px-4 py-3"><div class="flex space-x-2">
<button onclick="editRecord('${record.id}')" class="text-blue-600 hover:text-blue-800 transition-colors"><i class="fas fa-edit"></i></button>
<button onclick="deleteRecord('${record.id}')" class="text-red-600 hover:text-red-800 transition-colors"><i class="fas fa-trash"></i></button>
const data = this.getData();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `backup_dados_${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(a); a.click(); document.body.removeChild(a);
showNotification(message,type){
console.log(`${type.toUpperCase()}: ${message}`);
const dataManager = new DataManager();
// ==== Funções Globais ====
function addNewRecord() {
const name = prompt("Nome do registo:");
const description = prompt("Descrição (opcional):");
dataManager.addRecord({name, description});
const data = dataManager.getData();
const record = data.records.find(r => r.id===id);
const newName = prompt("Actualizar nome:", record.name);
const newDescription = prompt("Actualizar descrição:", record.description || '');
dataManager.updateRecord(id, {name:newName, description:newDescription});
function deleteRecord(id){ if(confirm("Deseja realmente eliminar este registo?")) dataManager.deleteRecord(id); }
if(confirm("Deseja eliminar todos os registos e redefinir o sistema?")){
localStorage.removeItem(dataManager.storageKey);
dataManager.initializeData();
// ==== Pesquisa dinâmica ====
document.getElementById('searchInput').addEventListener('input', (e)=>{
const query = e.target.value;
const filtered = dataManager.searchRecords(query);
const tableBody = document.getElementById('dataTableBody');
tableBody.innerHTML = `<tr><td colspan="5" class="px-4 py-8 text-center text-gray-500"><i class="fas fa-search text-4xl mb-2"></i><p>Nenhum resultado</p></td></tr>`;
tableBody.innerHTML = filtered.map(record => `
<tr class="border-b border-gray-200 hover:bg-gray-50 transition-colors">
<td class="px-4 py-3 text-sm text-gray-700">${record.id.slice(-6)}</td>
<td class="px-4 py-3"><div class="text-sm font-medium text-gray-900">${record.name}</div>${record.description ? `<div class="text-sm text-gray-500">${record.description}</div>` : ''}</td>
<td class="px-4 py-3"><span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${record.status==='active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">${record.status==='active' ? 'Activo':'Inactivo'}</span></td>
<td class="px-4 py-3 text-sm text-gray-500">${new Date(record.createdAt).toLocaleDateString('pt-PT')}</td>
<td class="px-4 py-3"><div class="flex space-x-2">
<button onclick="editRecord('${record.id}')" class="text-blue-600 hover:text-blue-800 transition-colors"><i class="fas fa-edit"></i></button>
<button onclick="deleteRecord('${record.id}')" class="text-red-600 hover:text-red-800 transition-colors"><i class="fas fa-trash"></i></button>
// ==== Abrir links e exportar para TXT ====
document.getElementById('openLinksBtn').addEventListener('click', ()=>{
const browser = document.getElementById('browserSelect').value;
const sites = dataManager.getData().integratedSites || [];
sites.forEach(site => { window.open(site, '_blank'); console.log(`Abrindo ${site} no navegador: ${browser}`); });
document.getElementById('saveTxtBtn').addEventListener('click', ()=>{
const data = dataManager.getData();
let txtContent = "Base de Dados - Cegonha 23\n\n";
if(data.records.length > 0){
txtContent += "Registos:\n";
data.records.forEach(r=>{
txtContent += `ID: ${r.id}\nNome: ${r.name}\nDescrição: ${r.description || '-'}\nStatus: ${r.status}\nData: ${new Date(r.createdAt).toLocaleString('pt-PT')}\n\n`;
if(data.integratedSites && data.integratedSites.length > 0){
txtContent += "Sites Integrados:\n";
data.integratedSites.forEach((site,i)=> { txtContent += `${i+1}. ${site}\n`; });
const blob = new Blob([txtContent],{type:"text/plain"});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = `Cegonha23_${new Date().toISOString().split('T')[0]}.txt`;
document.body.appendChild(a); a.click(); document.body.removeChild(a);