Initial production backup

This commit is contained in:
Tesscorp
2026-07-15 19:45:08 -06:00
commit 65b7af866f
433 changed files with 24089 additions and 0 deletions
+190
View File
@@ -0,0 +1,190 @@
<?php
require_once __DIR__ . '/auth.php';
requireLogin();
// Handle logout
if (isset($_GET['logout'])) {
session_destroy();
header('Location: ' . BLOG_URL . '/admin/login.php');
exit;
}
$db = getDB();
$admin = getAdminUser();
// Get all posts
$posts = $db->query("SELECT p.*, c.name AS category_name
FROM blog_posts p
LEFT JOIN blog_categories c ON p.category_id = c.id
ORDER BY p.created_at DESC")->fetchAll();
$totalPublished = 0;
$totalDrafts = 0;
foreach ($posts as $p) {
if ($p['status'] === 'published') $totalPublished++;
else $totalDrafts++;
}
$categories = $db->query("SELECT COUNT(*) FROM blog_categories")->fetchColumn();
// Flash message
$flash = $_SESSION['flash'] ?? '';
unset($_SESSION['flash']);
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100..900&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Dashboard - Blog Admin</title>
<style>
* { font-family: 'Montserrat', sans-serif; }
body { background: #f4f6fa; }
.admin-header {
background: linear-gradient(135deg, #0a1d3b, #0e55bb);
color: white;
padding: 1rem 0;
}
.stat-card {
border: none; border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
transition: transform 0.2s;
}
.stat-card:hover { transform: translateY(-3px); }
.stat-card .stat-number {
font-size: 2rem; font-weight: 800; color: #0a1d3b;
}
.stat-card .stat-label {
font-size: 0.8rem; color: #888; text-transform: uppercase; letter-spacing: 1px;
}
.table-posts { border-radius: 12px; overflow: hidden; }
.table-posts th {
background: #f8fafd; color: #0a1d3b;
font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;
border: none;
}
.table-posts td { vertical-align: middle; font-size: 0.9rem; }
.badge-pub { background: #d4edda; color: #155724; }
.badge-draft { background: #fff3cd; color: #856404; }
.btn-new {
background: linear-gradient(135deg, #0e55bb, #1186cc);
border: none; color: white; font-weight: 700;
border-radius: 10px; padding: 10px 24px;
}
.btn-new:hover { color: white; box-shadow: 0 6px 16px rgba(14,85,187,0.3); }
</style>
</head>
<body>
<!-- Header -->
<div class="admin-header">
<div class="container d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center gap-3">
<img src="<?= SITE_URL ?>/assets/img/trimape-logo-512-150x150.png" alt="TRIMAPE" style="height: 36px; border-radius: 6px;">
<div>
<strong>Blog Admin</strong>
<small class="d-block" style="opacity: 0.7; font-size: 0.75rem;">Hola, <?= e($admin['username'] ?? 'Admin') ?></small>
</div>
</div>
<div class="d-flex gap-2">
<a href="<?= BLOG_URL ?>" class="btn btn-sm btn-outline-light" target="_blank">Ver blog</a>
<a href="?logout=1" class="btn btn-sm btn-outline-light">Cerrar sesión</a>
</div>
</div>
</div>
<div class="container py-4">
<?php if ($flash): ?>
<div class="alert alert-success alert-dismissible fade show" style="border-radius: 10px;">
<?= e($flash) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<!-- Stats -->
<div class="row g-3 mb-4">
<div class="col-6 col-md-3">
<div class="card stat-card p-3 text-center">
<div class="stat-number"><?= $totalPublished ?></div>
<div class="stat-label">Publicados</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card p-3 text-center">
<div class="stat-number"><?= $totalDrafts ?></div>
<div class="stat-label">Borradores</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card p-3 text-center">
<div class="stat-number"><?= $categories ?></div>
<div class="stat-label">Categorías</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card p-3 text-center">
<div class="stat-number"><?= count($posts) ?></div>
<div class="stat-label">Total Posts</div>
</div>
</div>
</div>
<!-- Actions bar -->
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="fw-bold mb-0" style="color: #0a1d3b;">Artículos</h5>
<div class="d-flex gap-2">
<a href="categories.php" class="btn btn-sm btn-outline-primary" style="border-radius: 8px;">Categorías</a>
<a href="editor.php" class="btn btn-sm btn-new">+ Nuevo artículo</a>
</div>
</div>
<!-- Posts table -->
<div class="card border-0 shadow-sm" style="border-radius: 12px;">
<?php if (empty($posts)): ?>
<div class="card-body text-center py-5 text-muted">
<p>No hay artículos aún.</p>
<a href="editor.php" class="btn btn-new">Crear el primero</a>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-posts table-hover mb-0">
<thead>
<tr>
<th class="ps-3">Título</th>
<th>Categoría</th>
<th>Estado</th>
<th>Fecha</th>
<th class="text-end pe-3">Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($posts as $p): ?>
<tr>
<td class="ps-3 fw-bold"><?= e($p['title']) ?></td>
<td><span class="text-muted"><?= e($p['category_name'] ?? '—') ?></span></td>
<td>
<span class="badge rounded-pill <?= $p['status'] === 'published' ? 'badge-pub' : 'badge-draft' ?>">
<?= $p['status'] === 'published' ? 'Publicado' : 'Borrador' ?>
</span>
</td>
<td class="text-muted" style="font-size: 0.8rem;">
<?= $p['published_at'] ? date('d/m/Y', strtotime($p['published_at'])) : '—' ?>
</td>
<td class="text-end pe-3">
<a href="editor.php?id=<?= $p['id'] ?>" class="btn btn-sm btn-outline-primary" style="border-radius: 6px;">Editar</a>
<a href="delete.php?id=<?= $p['id'] ?>" class="btn btn-sm btn-outline-danger" style="border-radius: 6px;"
onclick="return confirm('¿Eliminar este artículo?')">Eliminar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>