Add usePageTitle so public and admin pages set document.title to the current page (e.g. Portfolio · jmartgraphix).
91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { Link, NavLink, Outlet, useLocation, useNavigate } from "react-router-dom";
|
|
import { api } from "../../lib/api";
|
|
import { usePageTitle } from "../../lib/pageTitle";
|
|
import "./Admin.scss";
|
|
|
|
function adminTitleFromPath(pathname: string): string {
|
|
if (pathname.endsWith("/projects/new")) return "New project · Admin";
|
|
if (/\/projects\/[^/]+$/.test(pathname) && !pathname.endsWith("/projects"))
|
|
return "Edit project · Admin";
|
|
if (pathname.includes("/projects")) return "Projects · Admin";
|
|
if (pathname.includes("/categories")) return "Categories · Admin";
|
|
if (pathname.includes("/views")) return "Portfolio views · Admin";
|
|
if (pathname.includes("/resume")) return "Resume · Admin";
|
|
if (pathname.includes("/settings")) return "Settings · Admin";
|
|
return "Admin";
|
|
}
|
|
|
|
export function AdminLayout() {
|
|
const [user, setUser] = useState<{ username: string; name?: string } | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
usePageTitle(adminTitleFromPath(location.pathname));
|
|
|
|
useEffect(() => {
|
|
api
|
|
.me()
|
|
.then(setUser)
|
|
.catch((e) => setError(e.message));
|
|
}, []);
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="admin-auth-error">
|
|
<h1>Admin access required</h1>
|
|
<p>
|
|
This area is protected by Authelia SSO via the <code>Remote-User</code> header.
|
|
</p>
|
|
<p className="admin-auth-error__detail">{error}</p>
|
|
<p>
|
|
Sign in at{" "}
|
|
<a href="https://auth.jmartgraphix.com">auth.jmartgraphix.com</a>, then return here.
|
|
</p>
|
|
<Link to="/" className="btn btn--ghost">
|
|
Back to site
|
|
</Link>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!user) {
|
|
return (
|
|
<div className="admin-auth-error">
|
|
<p>Checking authentication…</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="admin-shell">
|
|
<aside className="admin-nav">
|
|
<div className="admin-nav__brand">
|
|
<Link to="/admin">jmartgraphix</Link>
|
|
<span>Admin</span>
|
|
</div>
|
|
<nav>
|
|
<NavLink to="/admin" end>
|
|
Dashboard
|
|
</NavLink>
|
|
<NavLink to="/admin/projects">Projects</NavLink>
|
|
<NavLink to="/admin/categories">Categories & Tags</NavLink>
|
|
<NavLink to="/admin/views">Portfolio Views</NavLink>
|
|
<NavLink to="/admin/resume">Resume</NavLink>
|
|
<NavLink to="/admin/settings">Settings</NavLink>
|
|
</nav>
|
|
<div className="admin-nav__user">
|
|
<span>{user.name || user.username}</span>
|
|
<button type="button" className="btn btn--ghost btn--sm" onClick={() => navigate("/")}>
|
|
View site
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
<div className="admin-content">
|
|
<Outlet />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|