feat(nav): admin section label + role chip beside the user name

- A clearer 'Admin' section header (thicker centred rule when collapsed) above the
  admin-only modules (Scheduler/Configuration/Users), replacing the faint hairline.
- A small role chip (admin/user/demo) next to the account name — an avatar-corner dot
  when the rail is collapsed.
This commit is contained in:
npeter83 2026-07-01 22:50:59 +02:00
parent b7c79cbe53
commit b59208e006
4 changed files with 69 additions and 11 deletions

View file

@ -171,6 +171,21 @@ export default function NavSidebar({
const rowBase =
"w-full flex items-center gap-3 rounded-lg px-2.5 py-2 text-sm transition";
const name = me.display_name ?? me.email.split("@")[0];
// Role shown next to the name (expanded) / as an avatar dot (collapsed). Demo isn't a real
// role (it's a flag on a `user` row), so surface it first.
const roleKey: "admin" | "user" | "demo" = me.is_demo
? "demo"
: me.role === "admin"
? "admin"
: "user";
const roleChipCls =
roleKey === "admin"
? "bg-accent/15 text-accent"
: roleKey === "demo"
? "bg-amber-500/20 text-amber-500"
: "bg-muted/15 text-muted";
const roleDotCls =
roleKey === "admin" ? "bg-accent" : roleKey === "demo" ? "bg-amber-500" : "bg-muted";
const renderItem = ({ page: p, icon: Icon, label, badge }: NavItem) => {
const active = page === p;
@ -247,9 +262,19 @@ export default function NavSidebar({
<div className="flex-1 min-h-0 overflow-y-auto flex flex-col gap-1">
{userItems.map(renderItem)}
{systemItems.length > 0 && (
<div className="my-1.5 border-t border-border/70" />
)}
{systemItems.length > 0 &&
(collapsed ? (
// Collapsed rail: a short, thicker centred rule is the clearest "new section" cue
// when there's no room for a label.
<div className="my-2 mx-auto w-7 border-t-2 border-border" />
) : (
<div className="mt-4 mb-1 px-2.5 flex items-center gap-2">
<span className="text-[10px] font-semibold uppercase tracking-wider text-muted/70">
{t("nav.adminSection")}
</span>
<span className="flex-1 border-t border-border" />
</div>
))}
{systemItems.map(renderItem)}
</div>
@ -290,12 +315,27 @@ export default function NavSidebar({
title={collapsed ? name : undefined}
className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} text-muted hover:text-fg hover:bg-card`}
>
<span className="relative shrink-0">
<AvatarImg
src={me.avatar_url}
fallback={name}
className="w-[22px] h-[22px] rounded-full text-[10px] shrink-0"
className="w-[22px] h-[22px] rounded-full text-[10px]"
/>
{collapsed && (
<span
className={`absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full ring-2 ring-bg ${roleDotCls}`}
title={t(`nav.role.${roleKey}`)}
/>
)}
</span>
{!collapsed && <span className="truncate flex-1 text-left">{name}</span>}
{!collapsed && (
<span
className={`shrink-0 text-[10px] font-semibold uppercase tracking-wide px-1.5 py-0.5 rounded ${roleChipCls}`}
>
{t(`nav.role.${roleKey}`)}
</span>
)}
</button>
{acctOpen &&

View file

@ -1,5 +1,11 @@
{
"primary": "Hauptnavigation",
"collapse": "Seitenleiste einklappen",
"expand": "Seitenleiste ausklappen"
"expand": "Seitenleiste ausklappen",
"adminSection": "Admin",
"role": {
"admin": "Admin",
"user": "Benutzer",
"demo": "Demo"
}
}

View file

@ -1,5 +1,11 @@
{
"primary": "Primary navigation",
"collapse": "Collapse sidebar",
"expand": "Expand sidebar"
"expand": "Expand sidebar",
"adminSection": "Admin",
"role": {
"admin": "Admin",
"user": "User",
"demo": "Demo"
}
}

View file

@ -1,5 +1,11 @@
{
"primary": "Fő navigáció",
"collapse": "Oldalsáv összecsukása",
"expand": "Oldalsáv kinyitása"
"expand": "Oldalsáv kinyitása",
"adminSection": "Admin",
"role": {
"admin": "Admin",
"user": "Felhasználó",
"demo": "Demó"
}
}