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:
parent
b7c79cbe53
commit
b59208e006
4 changed files with 69 additions and 11 deletions
|
|
@ -171,6 +171,21 @@ export default function NavSidebar({
|
||||||
const rowBase =
|
const rowBase =
|
||||||
"w-full flex items-center gap-3 rounded-lg px-2.5 py-2 text-sm transition";
|
"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];
|
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 renderItem = ({ page: p, icon: Icon, label, badge }: NavItem) => {
|
||||||
const active = page === p;
|
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">
|
<div className="flex-1 min-h-0 overflow-y-auto flex flex-col gap-1">
|
||||||
{userItems.map(renderItem)}
|
{userItems.map(renderItem)}
|
||||||
{systemItems.length > 0 && (
|
{systemItems.length > 0 &&
|
||||||
<div className="my-1.5 border-t border-border/70" />
|
(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)}
|
{systemItems.map(renderItem)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -290,12 +315,27 @@ export default function NavSidebar({
|
||||||
title={collapsed ? name : undefined}
|
title={collapsed ? name : undefined}
|
||||||
className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} text-muted hover:text-fg hover:bg-card`}
|
className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} text-muted hover:text-fg hover:bg-card`}
|
||||||
>
|
>
|
||||||
|
<span className="relative shrink-0">
|
||||||
<AvatarImg
|
<AvatarImg
|
||||||
src={me.avatar_url}
|
src={me.avatar_url}
|
||||||
fallback={name}
|
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="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>
|
</button>
|
||||||
|
|
||||||
{acctOpen &&
|
{acctOpen &&
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"primary": "Hauptnavigation",
|
"primary": "Hauptnavigation",
|
||||||
"collapse": "Seitenleiste einklappen",
|
"collapse": "Seitenleiste einklappen",
|
||||||
"expand": "Seitenleiste ausklappen"
|
"expand": "Seitenleiste ausklappen",
|
||||||
|
"adminSection": "Admin",
|
||||||
|
"role": {
|
||||||
|
"admin": "Admin",
|
||||||
|
"user": "Benutzer",
|
||||||
|
"demo": "Demo"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"primary": "Primary navigation",
|
"primary": "Primary navigation",
|
||||||
"collapse": "Collapse sidebar",
|
"collapse": "Collapse sidebar",
|
||||||
"expand": "Expand sidebar"
|
"expand": "Expand sidebar",
|
||||||
|
"adminSection": "Admin",
|
||||||
|
"role": {
|
||||||
|
"admin": "Admin",
|
||||||
|
"user": "User",
|
||||||
|
"demo": "Demo"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"primary": "Fő navigáció",
|
"primary": "Fő navigáció",
|
||||||
"collapse": "Oldalsáv összecsukása",
|
"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ó"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue