163 lines
7.4 KiB
PHP
163 lines
7.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/bootstrap.php';
|
|
|
|
function render_brand_mark(string $projectName, string $extraClass = ''): void
|
|
{
|
|
$logoUrl = public_asset_url(app_logo_url());
|
|
$className = trim('brand-mark ' . $extraClass . ($logoUrl !== '' ? ' brand-mark-image' : ''));
|
|
?>
|
|
<span class="<?= e($className) ?>">
|
|
<?php if ($logoUrl !== ''): ?>
|
|
<img src="<?= e($logoUrl) ?>" alt="<?= e($projectName) ?> logo">
|
|
<?php else: ?>
|
|
<?= e(app_brand_initial()) ?>
|
|
<?php endif; ?>
|
|
</span>
|
|
<?php
|
|
}
|
|
|
|
function render_page_start(array $options = []): void
|
|
{
|
|
$title = $options['title'] ?? 'ServisIngat';
|
|
$description = $options['description'] ?? app_env('PROJECT_DESCRIPTION', 'Dashboard pengingat servis kendaraan agar tidak telat ganti oli, filter, CVT, gardan, busi, dan servis rutin lainnya.');
|
|
$page = $options['page'] ?? '';
|
|
$robots = $options['robots'] ?? 'index, follow';
|
|
$projectName = app_project_name();
|
|
$projectDescription = app_env('PROJECT_DESCRIPTION', $description);
|
|
$projectImageUrl = app_env('PROJECT_IMAGE_URL', '');
|
|
$isLoggedIn = is_user_logged_in();
|
|
$userName = current_user_name();
|
|
$bodyClass = trim('app-body page-' . ($page !== '' ? $page : 'default') . ' ' . (string) ($options['body_class'] ?? ''));
|
|
?>
|
|
<!doctype html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= e($title) ?> · <?= e($projectName) ?></title>
|
|
<meta name="description" content="<?= e($description) ?>">
|
|
<meta name="robots" content="<?= e($robots) ?>">
|
|
<meta property="og:title" content="<?= e($title . ' · ' . $projectName) ?>">
|
|
<meta property="og:description" content="<?= e($projectDescription) ?>">
|
|
<meta property="twitter:title" content="<?= e($title . ' · ' . $projectName) ?>">
|
|
<meta property="twitter:description" content="<?= e($projectDescription) ?>">
|
|
<?php if ($projectImageUrl): ?>
|
|
<meta property="og:image" content="<?= e($projectImageUrl) ?>">
|
|
<meta property="twitter:image" content="<?= e($projectImageUrl) ?>">
|
|
<?php endif; ?>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
<link rel="stylesheet" href="<?= e(asset_url('assets/css/custom.css')) ?>?v=<?= urlencode((string) filemtime(__DIR__ . '/../assets/css/custom.css')) ?>">
|
|
<?php $faviconUrl = public_asset_url(app_favicon_url()); ?>
|
|
<?php if ($faviconUrl !== ''): ?>
|
|
<link rel="icon" type="image/x-icon" href="<?= e($faviconUrl) ?>">
|
|
<?php endif; ?>
|
|
<?php $headCode = head_ad_code(); ?>
|
|
<?php if ($headCode !== ''): ?>
|
|
<?= $headCode ?>
|
|
<?php endif; ?>
|
|
</head>
|
|
<body class="<?= e($bodyClass) ?>">
|
|
<?php $bodyCode = body_ad_code(); ?>
|
|
<?php if ($bodyCode !== ''): ?>
|
|
<?= $bodyCode ?>
|
|
<?php endif; ?>
|
|
<header class="site-header border-bottom sticky-top">
|
|
<nav class="navbar navbar-expand-lg navbar-light">
|
|
<div class="container py-2">
|
|
<div class="nav-shell w-100 d-flex align-items-center justify-content-between gap-3">
|
|
<a class="navbar-brand d-flex align-items-center gap-3 fw-semibold text-dark m-0" href="<?= e(app_url()) ?>" aria-label="<?= e($projectName) ?> beranda">
|
|
<?php render_brand_mark($projectName); ?>
|
|
<span>
|
|
<span class="brand-title"><?= e($projectName) ?></span>
|
|
<span class="brand-subtitle">maintenance tracker</span>
|
|
</span>
|
|
</a>
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav" aria-controls="mainNav" aria-expanded="false" aria-label="Buka navigasi">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="mainNav">
|
|
<ul class="navbar-nav ms-auto align-items-lg-center gap-lg-2">
|
|
<li class="nav-item"><a class="nav-link <?= $page === 'home' ? 'active' : '' ?>" href="<?= e(app_url()) ?>">Beranda</a></li>
|
|
<li class="nav-item"><a class="nav-link <?= in_array($page, ['dashboard', 'detail'], true) ? 'active' : '' ?>" href="<?= e(app_url('dashboard.php')) ?>">Dashboard</a></li>
|
|
<?php if ($isLoggedIn): ?>
|
|
<li class="nav-item"><span class="nav-user-badge"><?= e($userName) ?></span></li>
|
|
<li class="nav-item ms-lg-2"><a class="btn btn-dark btn-sm px-3" href="<?= e(app_url('logout.php')) ?>">Logout</a></li>
|
|
<?php else: ?>
|
|
<li class="nav-item"><a class="nav-link <?= $page === 'login' ? 'active' : '' ?>" href="<?= e(app_url('login.php')) ?>">Login</a></li>
|
|
<li class="nav-item"><a class="nav-link <?= $page === 'register' ? 'active' : '' ?>" href="<?= e(app_url('register.php')) ?>">Daftar</a></li>
|
|
<li class="nav-item ms-lg-2"><a class="btn btn-dark btn-sm px-3" href="<?= e(app_url('register.php')) ?>">Mulai Catat</a></li>
|
|
<?php endif; ?>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
<main>
|
|
<?php
|
|
}
|
|
|
|
function render_flash(?array $flash): void
|
|
{
|
|
if (!$flash || empty($flash['message'])) {
|
|
return;
|
|
}
|
|
|
|
$type = (string) ($flash['type'] ?? 'info');
|
|
$message = (string) $flash['message'];
|
|
$color = match ($type) {
|
|
'success' => 'success',
|
|
'warning' => 'warning',
|
|
'danger', 'error' => 'danger',
|
|
default => 'secondary',
|
|
};
|
|
?>
|
|
<div class="toast-container position-fixed top-0 end-0 p-3">
|
|
<div class="toast align-items-center text-bg-<?= e($color) ?> border-0 show app-toast" role="status" aria-live="polite" aria-atomic="true" data-bs-delay="5000">
|
|
<div class="d-flex">
|
|
<div class="toast-body"><?= e($message) ?></div>
|
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Tutup"></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
function render_page_end(): void
|
|
{
|
|
$projectName = app_project_name();
|
|
?>
|
|
</main>
|
|
<footer class="site-footer border-top mt-5">
|
|
<div class="container py-4 py-lg-5">
|
|
<div class="footer-shell d-flex flex-column flex-lg-row justify-content-between gap-4 align-items-lg-center">
|
|
<div>
|
|
<div class="footer-brand d-flex align-items-center gap-3 mb-2">
|
|
<?php render_brand_mark($projectName, 'brand-mark-sm'); ?>
|
|
<div>
|
|
<div class="fw-semibold text-dark"><?= e($projectName) ?></div>
|
|
<div class="small text-muted">MVP pengingat servis kendaraan multi-user untuk motor, mobil, dan bengkel kecil.</div>
|
|
</div>
|
|
</div>
|
|
<div class="footer-chips d-flex flex-wrap gap-2">
|
|
<span class="summary-chip">Dashboard privat</span>
|
|
<span class="summary-chip">Reminder terstruktur</span>
|
|
<span class="summary-chip">Multi-user aman</span>
|
|
</div>
|
|
</div>
|
|
<div class="small text-muted text-lg-end">
|
|
Data servis tiap akun dipisahkan agar tidak saling terlihat.<br>
|
|
<a class="text-decoration-none" href="<?= e(app_url('healthz.php')) ?>">Health check</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
|
<script src="<?= e(asset_url('assets/js/main.js')) ?>?v=<?= urlencode((string) filemtime(__DIR__ . '/../assets/js/main.js')) ?>"></script>
|
|
</body>
|
|
</html>
|
|
<?php
|
|
}
|