39301-vm/includes/admin_layout.php
2026-04-09 18:45:07 +00:00

208 lines
8.4 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/library.php';
function admin_render_header(string $title, string $activePage = 'dashboard'): void {
library_bootstrap();
$lang = library_get_language();
$dir = $lang === 'ar' ? 'rtl' : 'ltr';
$isRtl = $lang === 'ar';
$profile = library_get_profile();
$brandName = library_profile_name($lang);
$brandTagline = library_profile_tagline($lang);
$brandShortName = trim((string) ($profile['short_name'] ?? '')) ?: 'NL';
$logoPath = trim((string) ($profile['logo_path'] ?? ''));
$faviconPath = trim((string) ($profile['favicon_path'] ?? ''));
$flashes = [];
if (isset($_SESSION['library_flash'])) {
$flashes = $_SESSION['library_flash'];
unset($_SESSION['library_flash']);
}
?>
<!doctype html>
<html lang="<?= $lang ?>" dir="<?= $dir ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= h($title) ?> · <?= library_trans('admin_panel') ?></title>
<?php if ($faviconPath !== ''): ?>
<link rel="icon" href="/<?= h($faviconPath) ?>?v=<?= time() ?>" sizes="any">
<link rel="shortcut icon" href="/<?= h($faviconPath) ?>?v=<?= time() ?>">
<?php endif; ?>
<?php if ($isRtl): ?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.rtl.min.css" integrity="sha384-dpuaG1suU0eT09tx5plTaGMLBsfDLzUCCUXOY2j/LSvXYuG6Bqs43ALlhIqAJVRb" crossorigin="anonymous">
<?php else: ?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<?php endif; ?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<style>
.admin-sidebar {
width: 280px;
height: 100vh;
position: sticky;
top: 0;
background: #fff;
border-<?= $isRtl ? 'left' : 'right' ?>: 1px solid #dee2e6;
padding: 20px;
}
.nav-link {
color: #333;
margin-bottom: 0.25rem;
}
.nav-link:hover {
background-color: #f8f9fa;
}
.nav-link.active {
background-color: #e9ecef;
color: #0d6efd !important;
font-weight: 500;
}
.admin-brand-card {
border: 1px solid #e9ecef;
background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
}
.admin-brand-logo,
.admin-brand-mark {
width: 52px;
height: 52px;
border-radius: 16px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.admin-brand-logo {
object-fit: cover;
border: 1px solid #e9ecef;
background: #fff;
}
.admin-brand-mark {
background: linear-gradient(135deg, #51d0ff, #ff9c52);
color: #07111b;
font-weight: 800;
letter-spacing: .08em;
}
</style>
</head>
<body class="bg-light">
<div class="d-flex">
<aside class="admin-sidebar d-flex flex-column">
<div class="card admin-brand-card shadow-sm rounded-4 mb-4">
<div class="card-body p-3">
<div class="d-flex align-items-center gap-3">
<?php if ($logoPath !== ''): ?>
<img src="/<?= h($logoPath) ?>?v=<?= time() ?>" alt="<?= h($brandName) ?> logo" class="admin-brand-logo">
<?php else: ?>
<span class="admin-brand-mark"><?= h($brandShortName) ?></span>
<?php endif; ?>
<div>
<div class="fw-bold text-primary"><?= h($brandName) ?></div>
<?php if ($brandTagline !== ''): ?>
<div class="small text-secondary"><?= h($brandTagline) ?></div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<div class="mb-3">
<a href="?lang=<?= library_trans('switch_lang_code') ?>" class="btn btn-sm btn-outline-secondary w-100">
<i class="bi bi-translate me-2"></i><?= library_trans('switch_lang') ?>
</a>
</div>
<nav class="nav flex-column flex-grow-1">
<a class="nav-link rounded <?= $activePage === 'dashboard' ? 'active' : '' ?>" href="/admin.php">
<i class="bi bi-speedometer2 me-2"></i> <?= library_trans('dashboard') ?>
</a>
<a class="nav-link rounded <?= $activePage === 'library_profile' ? 'active' : '' ?>" href="/admin_library_profile.php">
<i class="bi bi-building-gear me-2"></i> <?= $isRtl ? 'ملف المكتبة' : 'Library Profile' ?>
</a>
<a class="nav-link rounded <?= $activePage === 'documents' ? 'active' : '' ?>" href="/admin_documents.php">
<i class="bi bi-folder2-open me-2"></i> <?= library_trans('material_entry') ?>
</a>
<div class="my-2 border-top"></div>
<a class="nav-link rounded <?= $activePage === 'categories' ? 'active' : '' ?>" href="/admin_categories.php">
<i class="bi bi-tags me-2"></i> <?= library_trans('categories') ?>
</a>
<a class="nav-link rounded <?= $activePage === 'subcategories' ? 'active' : '' ?>" href="/admin_subcategories.php">
<i class="bi bi-diagram-3 me-2"></i> <?= library_trans('subcategories') ?>
</a>
<a class="nav-link rounded <?= $activePage === 'types' ? 'active' : '' ?>" href="/admin_types.php">
<i class="bi bi-file-earmark-text me-2"></i> <?= library_trans('types') ?>
</a>
</nav>
<div class="mt-auto pt-3 border-top">
<a class="nav-link text-secondary rounded" href="/index.php">
<i class="bi bi-box-arrow-right me-2"></i> <?= library_trans('return_to_site') ?>
</a>
</div>
</aside>
<main class="flex-grow-1 p-4" style="min-width: 0;">
<header class="mb-4 border-bottom pb-2">
<h2 class="h3"><?= h($title) ?></h2>
</header>
<?php foreach ($flashes as $flash): ?>
<div class="alert alert-<?= $flash['type'] === 'error' ? 'danger' : 'success' ?> alert-dismissible fade show shadow-sm" role="alert">
<?= h($flash['message']) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endforeach; ?>
<?php
}
function admin_render_footer(): void {
?>
</main>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
async function translateText(sourceId, targetId, targetLang) {
const source = document.getElementById(sourceId);
const target = document.getElementById(targetId);
const text = source.value.trim();
if (!text) {
alert(<?= json_encode(library_trans('translation_enter_text')) ?>);
return;
}
const originalPlaceholder = target.placeholder;
target.placeholder = <?= json_encode(library_trans('translating')) ?>;
const originalOpacity = target.style.opacity;
target.style.opacity = '0.7';
try {
const response = await fetch('/api/translate.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text, target_lang: targetLang })
});
if (!response.ok) throw new Error(<?= json_encode(library_trans('translation_failed')) ?>);
const data = await response.json();
if (data.translation) {
target.value = data.translation;
} else if (data.error) {
alert(<?= json_encode(library_trans('translation_error_prefix')) ?> + ' ' + data.error);
}
} catch (e) {
console.error(e);
alert(<?= json_encode(library_trans('translation_failed')) ?>);
} finally {
target.placeholder = originalPlaceholder;
target.style.opacity = originalOpacity;
}
}
</script>
</body>
</html>
<?php
}
?>